您想要一个相当简单的 SELECT 查询和一些 LEFT/INNER JOIN(s)。
这个网站有一些很好的例子/解释似乎非常接近您的需要:https://www.mysqltutorial.org/mysql-inner-join.aspx
我会给你一个简单的例子,但我并不清楚相关列是什么数据类型。两个表的_id-columns 可能是 INTEGER 的一些变体,它们是否也是主键(或至少索引?),client_name/ticket_name 可能是 VARCHAR/TEXT/STRING 类型,但究竟是剩余的列存储?作为 json 或数组或? (+细节)
您还用PHP 标记了您的帖子,您是在SQL 查询之后吗?或寻找其中包含 SQL 的 PHP 代码。
更新
架构的改进版本
CREATE TABLE clients (
client_id SERIAL,
client_name VARCHAR(255) NOT NULL,
PRIMARY KEY (client_id)
);
CREATE TABLE tickets (
ticket_id SERIAL,
ticket_name VARCHAR(255) NOT NULL,
ticket_price DECIMAL(10,2) NOT NULL,
PRIMARY KEY (ticket_id)
);
-- A junction table to glue those 2 tables together (N to N relationship)
CREATE TABLE client_tickets (
client_id BIGINT UNSIGNED NOT NULL,
ticket_id BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (client_id, ticket_id)
);
我已更改数据类型。
client_name 和 ticket_name 仍然是 VARCHARS。我已将它们标记为NOT NULL(例如:必填字段),但如果您不喜欢,可以删除该部分。
client_id/ticket_id/ticket_price 也是 NOT NULL,但更改会产生负面影响。
ticket_price 现在是一个 DECIMAL 字段,可以存储诸如 1299.50 或 50.00 之类的数字2 位小数(美分)。所以你可以存储从 $ -99.999.999,99 到 $ 99.999.999,99 的任何东西。
在 SQL 中,总是用这种表示法写数字(比如 70k):70000.00(例如:点,而不是逗号;并且没有千位运算符)。
client_id 和ticket_id 现在都是SERIALs,这是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE 的简写,并且它们都是PRIMARY KEYs。这听起来可能很复杂,但它们仍然只是普通的INTEGERs,具有4 或12 等值。
UNIQUE 位防止您拥有 2 个具有相同 ID 号的客户端,AUTO_INCREMENT 意味着当您添加新客户端时,您不必指定 ID(尽管您可以这样做);你可以这样做:
INSERT INTO clients (client_name) values ('Fantastic Mr Fox');
client_id 将自动设置(随时间递增)。另一个表中的ticket_id 也是如此。
.
我已将您原来的 client_tickets 列替换为单独的连接表。
那里的记录存储客户的client_id 和属于他们的ticket_id。
一个客户端可以在联结表中有多个记录(他们拥有的每张票一个记录)。
同样,可以在任意数量的行上提及一张票。
某个client_id 可能在联结表中没有任何记录。
同样,某个ticket_id 可能在联结表中没有任何记录。
此表中不能存在相同的记录(由PRIMARY KEY 强制执行)。
测试数据
接下来,我们可以放一些数据来测试它:
-- Create some tickets
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (1, 'ticketone', '30' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (2, 'tickettwo', '40' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (3, 'ticketthree', '50' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (4, 'ticketfour', '60' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (5, 'ticketfive', '70' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (6, 'ticketsix', '4' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (7, 'ticketseven', '9' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (8, 'ticketeight', '500' );
-- Create some users, and link them to some of these tickets
INSERT INTO clients (client_id, client_name) values (1, 'John');
INSERT INTO client_tickets (client_id, ticket_id) values (1, 3);
INSERT INTO client_tickets (client_id, ticket_id) values (1, 7);
INSERT INTO client_tickets (client_id, ticket_id) values (1, 1);
INSERT INTO clients (client_id, client_name) values (2, 'Peter');
INSERT INTO client_tickets (client_id, ticket_id) values (2, 5);
INSERT INTO client_tickets (client_id, ticket_id) values (2, 2);
INSERT INTO client_tickets (client_id, ticket_id) values (2, 3);
INSERT INTO clients (client_id, client_name) values (3, 'Eddie');
INSERT INTO client_tickets (client_id, ticket_id) values (3, 8);
INSERT INTO clients (client_id, client_name) values (9, 'Fred');
-- Note: ticket #3 is owned by both client #1/#2;
-- Note: ticket #4 and #6 are unused;
-- Note: client #9 (Fred) has no tickets;
查询
获取所有现有关系(无票客户被排除在外,无所有者票被排除在外)
SELECT clients.*
, tickets.*
FROM client_tickets AS ct
INNER JOIN clients ON ct.client_id = clients.client_id
INNER JOIN tickets ON ct.ticket_id = tickets.ticket_id
ORDER BY clients.client_id ASC
, tickets.ticket_id ASC ;
获取所有仍然免费的门票(无所有者)
SELECT tickets.*
FROM tickets
WHERE tickets.ticket_id NOT IN (
SELECT ct.ticket_id
FROM client_tickets AS ct
)
ORDER BY tickets.ticket_id ASC ;
获取所有客户(甚至是无票客户)的列表,并包括每个客户有多少票以及他们的票的总价格。
SELECT clients.*
, COALESCE(COUNT(tickets.ticket_id), 0) AS amount_of_tickets
, COALESCE(SUM(tickets.ticket_price), 0.00) AS total_price
FROM clients
LEFT JOIN client_tickets AS ct ON ct.client_id = clients.client_id
LEFT JOIN tickets ON ct.ticket_id = tickets.ticket_id
GROUP BY clients.client_id
ORDER BY clients.client_id ASC ;
将所有有趣的信息放在一起(不包括无所有者门票)
SELECT clients.*
, COALESCE(COUNT(sub.ticket_id), 0) AS amount_of_tickets
, COALESCE(SUM(sub.ticket_price), 0.00) AS total_price
, JSON_ARRAYAGG(sub.js_tickets_row) AS js_tickets_rows
FROM clients
LEFT JOIN client_tickets AS ct ON ct.client_id = clients.client_id
LEFT JOIN (
SELECT tickets.*
, JSON_OBJECT( 'ticket_id', tickets.ticket_id
, 'ticket_name', tickets.ticket_name
, 'ticket_price', tickets.ticket_price
) AS js_tickets_row
FROM tickets
) AS sub ON ct.ticket_id = sub.ticket_id
GROUP BY clients.client_id
ORDER BY clients.client_id ASC ;
-- sidenote: output column `js_tickets_rows` (a json array) may contain NULL values
包含一些汇总数据的所有票证列表
SELECT tickets.*
, IF(COALESCE(COUNT(clients.client_id), 0) > 0
, TRUE, FALSE) AS active
, COALESCE( COUNT(clients.client_id), 0) AS amount_of_clients
, IF(COALESCE( COUNT(clients.client_id), 0) > 0
, GROUP_CONCAT(clients.client_name SEPARATOR ', ')
, NULL) AS client_names
FROM tickets
LEFT JOIN client_tickets AS ct ON ct.ticket_id = tickets.ticket_id
LEFT JOIN clients ON ct.client_id = clients.client_id
GROUP BY tickets.ticket_id
ORDER BY tickets.ticket_id ASC
, clients.client_id ASC ;