ORDER BY与DISTINCT三向左联合

时间:2016-07-03 21:23:21

标签: sql sqlite

请考虑以下表格。

CREATE TABLE asset (id INT PRIMARY KEY, ...other fields...);
CREATE TABLE property (id INT PRIMARY KEY, name TEXT, value INT);
CREATE TABLE asset_property (asset_id INT, property_id INT);

我希望选择资产并根据财产进行订购;但是,我希望将所有资产都包含在列表中,而不仅仅是那些具有我正在排序的属性的资产。例如,我可能有

INSERT INTO asset VALUES (1, ...);
INSERT INTO property VALUES (1, 'x', 50);
INSERT INTO property VALUES (2, 'y', 60);
INSERT INTO asset_property VALUES (1, 1);
INSERT INTO asset_property VALUES (1, 2);

INSERT INTO asset VALUES (2, ...);
INSERT INTO property VALUES (3, 'y', 70);
INSERT INTO asset_property VALUES (2, 3);

INSERT INTO asset VALUES (3, ...);
INSERT INTO property VALUES (4, 'x', 80);
INSERT INTO asset_property VALUES (3, 4);

INSERT INTO asset VALUES (4, ...);

我希望选择资产并按“x”属性进行排序。这对我来说听起来像是一个LEFT JOIN。

SELECT asset.* FROM asset
LEFT JOIN asset_property ON asset.id = asset_property.asset_id
LEFT JOIN property ON asset_property.asset_id = property.id
                      AND property.name = 'x'
ORDER BY property.value;

然而,精明的读者会注意到这会产生如下结果:

asset.id
1
3
1
2
4

资产1有两行,因为资产1具有名为“x”的属性,而另一行由于其具有未命名为“x”的属性而存在一行。

这是我的知识/理解不足的地方。为了回避这个问题,我尝试使用DISTINCT关键字。

SELECT DISTINCT asset.* FROM asset
LEFT JOIN asset_property ON asset.id = asset_property.asset_id
LEFT JOIN property ON asset_property.asset_id = property.id
                      AND property.name = 'x'
ORDER BY property.value;

这样做的问题在于,至少在SQLite(3.12.1)下,使用DISTINCT关键字似乎会覆盖ORDER BY子句:这些行按asset.id排序。

虽然我毫不怀疑这种数据库格式似乎是问题的根源,而不是我缺乏SQL魔法,但请保存你的能量,而不是建议我改变它;我知道该怎么做。虽然手头的任务可能不是 easy ,但我希望它是可能的,而且这种格式还有其它优点,可以让扭曲变得有价值。谢谢。

3 个答案:

答案 0 :(得分:1)

如果只想使用property.name ='x'的行,则应使用内连接..

SELECT asset.* FROM asset
LEFT JOIN asset_property ON asset.id = asset_property.asset_id
INNER JOIN property ON asset_property.asset_id = property.id
                  AND property.name = 'x'
ORDER BY property.value;

或者你最后的评论

SELECT asset.* FROM asset
LEFT JOIN asset_property ON asset.id = asset_property.asset_id
INNER JOIN property ON asset_property.property_id = property.id
                  AND property.name = 'x'
ORDER BY case property.value when is null the 1 else 0 end, property.value;

答案 1 :(得分:0)

对您的测试数据进行一些假设,您应该能够使用更多的SQL语法来避免使用paste

a.addEventListener('keyup', hidebravo);    
b.addEventListener('keyup', hidebravo);

子查询仅包含具有distinct属性的行,然后主表左连接到该属性。这可以避免每select a.id from asset a left join ( select asset_id, value from asset_property ap left join property p on p.id=ap.property_id where p.name = 'x' ) xp on a.id=xp.asset_id order by case when xp.value is null then 1 else 0 end, xp.value 个多行,假设每个资产只能有零个或x个属性。

答案 2 :(得分:0)

如果使用子选择怎么办:先选择distinct然后再订购?

Select * from (SELECT DISTINCT asset.*, property.value FROM asset LEFT JOIN asset_property ON asset.id = asset_property.asset_id LEFT JOIN property ON asset_property.asset_id = property.id AND property.name = 'x') ORDER BY property.value;

检查语法,只是试着解释一下这个方法。