SQL-基于多行按条件选择
我有两张桌子:SQL-基于多行按条件选择,sql,Sql,我有两张桌子: actions action_data action\u data属于actions,并具有以下列:action\u id,name,value 内容可能如下所示: SELECT DISTINCT actions.* FROM actions INNER JOIN action_data ON actions.id = action_data.action_id WHERE (action_data.name = 'planet'
actions
action_data
action\u data
属于actions,并具有以下列:action\u id
,name
,value
内容可能如下所示:
SELECT DISTINCT
actions.*
FROM
actions
INNER JOIN
action_data ON actions.id = action_data.action_id
WHERE
(action_data.name = 'planet' AND action_data.value = 'earth');
declare @t TABLE(id int, name NVARCHAR(MAX), value NVARCHAR(MAX))
INSERT INTO @t VALUES(1, 'planet', 'earth')
INSERT INTO @t VALUES(1, 'object', 'spaceship_a')
INSERT INTO @t VALUES(1, 'destination', 'mars')
SELECT * FROM @t t1
JOIN @t t2 ON t1.ID = t2.id
WHERE t1.name = 'planet' AND t1.value = 'earth'
AND t2.name = 'object' AND t2.value = 'spaceship_a'
SELECT DISTINCT action_id
FROM action_data a1 JOIN action_data a2 USING(action_id)
WHERE
a1.name = 'planet' AND a1.value = 'earth' AND
a2.name = 'object' AND a2.value = 'spaceship_a';
操作
:
id |
-----
178|
179|
操作\u数据
:
action_id | name | value
-------------------------------------
178 | planet | earth
178 | object | spaceship_a
179 | planet | earth
179 | object | building
现在我想选择动作,动作中有planet=earth和object=spaceship\u a
数据
如何使用SQL实现这一点?如果您只有一个条件,它的工作方式如下:
SELECT DISTINCT
actions.*
FROM
actions
INNER JOIN
action_data ON actions.id = action_data.action_id
WHERE
(action_data.name = 'planet' AND action_data.value = 'earth');
declare @t TABLE(id int, name NVARCHAR(MAX), value NVARCHAR(MAX))
INSERT INTO @t VALUES(1, 'planet', 'earth')
INSERT INTO @t VALUES(1, 'object', 'spaceship_a')
INSERT INTO @t VALUES(1, 'destination', 'mars')
SELECT * FROM @t t1
JOIN @t t2 ON t1.ID = t2.id
WHERE t1.name = 'planet' AND t1.value = 'earth'
AND t2.name = 'object' AND t2.value = 'spaceship_a'
SELECT DISTINCT action_id
FROM action_data a1 JOIN action_data a2 USING(action_id)
WHERE
a1.name = 'planet' AND a1.value = 'earth' AND
a2.name = 'object' AND a2.value = 'spaceship_a';
但是我需要来自操作\u数据的两个或多个条件
有什么想法吗?我使用分组方法和拥有方法来解决这些问题,因为这是一种非常通用的方法,适用于许多情况
就你而言:
select ad.action_id
from action_data ad
group by ad.action_id
having sum(case when name = 'planet' and value = 'earth' then 1 else 0 end) > 0 and
sum(case when name = 'object' and value = 'spaceship_a' then 1 else 0 end) > 0;
having
子句中的每个条件统计匹配的行数。>0
表示至少有一个
您可以join
返回到actions
表,以获取更多列(如果需要)。如果条件数量不变,可以使用join,这将比使用总和和大小写分组快得多
如果有两个条件,您可以这样加入:
SELECT DISTINCT
actions.*
FROM
actions
INNER JOIN
action_data ON actions.id = action_data.action_id
WHERE
(action_data.name = 'planet' AND action_data.value = 'earth');
declare @t TABLE(id int, name NVARCHAR(MAX), value NVARCHAR(MAX))
INSERT INTO @t VALUES(1, 'planet', 'earth')
INSERT INTO @t VALUES(1, 'object', 'spaceship_a')
INSERT INTO @t VALUES(1, 'destination', 'mars')
SELECT * FROM @t t1
JOIN @t t2 ON t1.ID = t2.id
WHERE t1.name = 'planet' AND t1.value = 'earth'
AND t2.name = 'object' AND t2.value = 'spaceship_a'
SELECT DISTINCT action_id
FROM action_data a1 JOIN action_data a2 USING(action_id)
WHERE
a1.name = 'planet' AND a1.value = 'earth' AND
a2.name = 'object' AND a2.value = 'spaceship_a';
当然,如果您有3个条件,则需要加入2次并添加新筛选器:
SELECT * FROM @t t1
JOIN @t t2 ON t1.ID = t2.id
JOIN @t t3 ON t1.ID = t3.id
WHERE t1.name = 'planet' AND t1.value = 'earth'
AND t2.name = 'object' AND t2.value = 'spaceship_a'
AND t3.name = 'destination' AND t3.value = 'mars'
如果不需要特定于DBMS的语法,可以使用自动联接
我会这样做:
SELECT DISTINCT
actions.*
FROM
actions
INNER JOIN
action_data ON actions.id = action_data.action_id
WHERE
(action_data.name = 'planet' AND action_data.value = 'earth');
declare @t TABLE(id int, name NVARCHAR(MAX), value NVARCHAR(MAX))
INSERT INTO @t VALUES(1, 'planet', 'earth')
INSERT INTO @t VALUES(1, 'object', 'spaceship_a')
INSERT INTO @t VALUES(1, 'destination', 'mars')
SELECT * FROM @t t1
JOIN @t t2 ON t1.ID = t2.id
WHERE t1.name = 'planet' AND t1.value = 'earth'
AND t2.name = 'object' AND t2.value = 'spaceship_a'
SELECT DISTINCT action_id
FROM action_data a1 JOIN action_data a2 USING(action_id)
WHERE
a1.name = 'planet' AND a1.value = 'earth' AND
a2.name = 'object' AND a2.value = 'spaceship_a';
这适用于2个条件,但可以扩展到3个或更多,使用FROM
子句中数据表的多个副本以及相应的比较条件
在这种情况下,a1
复制品用于第一种情况(行星-地球),而a2
复制品用于第二种情况(物体-宇宙飞船a)
JOIN
允许我们在所有可能的组合中搜索匹配项(N行给出N^2个组合)
这可能不是最好、最有效的方法,但它是可靠的,不依赖于平台
演示如下:
mysql> select * from action_data;
+-----------+--------+-------------+
| action_id | name | value |
+-----------+--------+-------------+
| 178 | planet | earth |
| 178 | object | spaceship_a |
| 179 | planet | earth |
| 179 | object | building |
+-----------+--------+-------------+
4 rows in set (0.02 sec)
mysql> SELECT DISTINCT action_id
-> FROM action_data a1 JOIN action_data a2 USING (action_id)
-> WHERE
-> a1.name = 'planet' AND a1.value = 'earth' AND
-> a2.name = 'object' AND a2.value = 'spaceship_a';
+-----------+
| action_id |
+-----------+
| 178 |
+-----------+
1 row in set (0.00 sec)
还有一些选择:
1) 使用存在
select *
from actions a
where exists (select 1 from action_data ad
where ad.action_id = a.id and ad.name = 'planet' and ad.value = 'earth')
and exists (select 1 from action_data ad
where ad.action_id = a.id and ad.name = 'object' and ad.value = 'spaceship_a');
2) 将与
with q1 as (
select action_id
from action_data
where name = 'planet' and value = 'earth'
),
q2 as (
select action_id
from action_data
where name = 'object' and value = 'spaceship_a'
)
select *
from q1 inner join q2 on q1.action_id = q2.action_id;
因为您不知道要搜索的元数据的数量,所以我不建议使用未知/无限数量的连接
改为使用组串联
:
select * from actions
join (
select action_id,
group_concat(name,'=',value order by name separator ',') as csv // MySQL
// string_agg(name || '=' || value, ',' order by name) as csv // PostgreSQL
from meta
where name in ('planet', 'object')
group by action_id
) meta
on actions.id = meta.action_id
where csv = 'object=building,planet=earth'
我很高兴听到SQL关于性能的建议,我想,如果要找到3+以上的值,性能会更好。数据透视表会工作吗?以什么方式工作?我认为数据透视表不起作用如果你提前知道你的“名字”,数据透视表最终会看起来像一个普通的表:where planet=earth and object=spaceship\u a你在用哪个数据库管理系统?博士后?神谕