sql 服务器 - 基于优先级列的不同选择
sql SERVER - distinct selection based on priority columns
你好,如果可能的话,我想找到一个解决方案来解决我的问题。
现在我把所有的记录都拿出来,然后我一条一条地检查那些我不想要的东西。
我有 2 个 table:第一个 table 有链接
第二个带有 url
的首选标签
必须查询第二个 table,只保留具有最高优先级的行
优先规则是
当前用户然后
用户组,最后
大家
如果隐藏列为真,则排除对 url
的任何引用
这是预期的结果。
不幸的是,除了将条件乘以多个选择和联合之外,我看不到任何其他解决方案。
如果您有解决我问题的想法,在此先感谢您的帮助
您似乎可以依靠 pref_id
进行偏好排序,对吗?如果是这样,你可以试试:
SELECT *
FROM table2
INNER JOIN table1 ON table2.url_id = table1.url_id
QUALIFY ROW_NUMBER() OVER (
PARTITION BY table1.url
ORDER BY pref_id ASC
) = 1
这将按 url 进行分区,然后仅提供 pref_id 最低的那个。
我没有测试这个 SQL 因为我不确定你 运行 在哪个 RDBMS 上,但我使用 Rasgo 来翻译 SQL .
可能对这个棘手的查询感兴趣:
select so.*, table1.url from
(select distinct t.url_id,
(select pref_id from table2 s where s.url_id = t.url_id order by "user" is null, "group" is null limit 1) pref_id
from table2 t
where not exists(select 1 from table2 s where s.hide and s.url_id = t.url_id)
) ids
join table2 so on so.pref_id = ids.pref_id
join table1 ON table1.url_id = ids.url_id
order by so.url_id;
这是我的解决方案,但我认为还有更好的办法。
在条件的select中,我建立了一个列,根据优先级
给出了级别注释
DECLARE @CUR_USER VARCHAR(10) = 'ROBERT'
DECLARE @CUR_GROUP VARCHAR(10) = 'DEV'
DECLARE @TABLE1 TABLE (
URL_ID INT
,URLNAME VARCHAR(100)
);
DECLARE @TABLE2 TABLE (
PREF_ID INT
,URL_ID INT
,FAVORITE_LABEL VARCHAR(100)
,USER_GROUP VARCHAR(10)
,USER_CODE VARCHAR(10)
,HIDE_URL DECIMAL(1, 0) DEFAULT 0
);
INSERT INTO @TABLE1
VALUES
(1, 'https://whosebug.com/')
,(2, 'https://www.microsoft.com/')
,(3, 'https://www.apple.com/')
,(4, 'https://www.wikipedia.org/')
;
INSERT INTO @TABLE2
VALUES
(1000, 1, 'find everything', NULL, 'ROBERT', 0)
,(1001, 1, 'a question ? find the answer here', 'DEV', NULL, 0)
,(1002, 1, 'Whosebug', NULL, NULL, 0)
,(1003, 2, 'Windows', 'DEV', NULL, 0)
,(1004, 2, 'Microsoft', NULL, NULL, 0)
,(1005, 3, 'Apple', NULL, NULL, 0)
,(1006, 4, 'Free encyclopedia', NULL, 'ROBERT', 1)
,(1007, 4, 'Wikipedia', NULL, NULL, 0)
,(1008, 1, 'Whosebug FOR MAT', 'MAT', NULL, 0)
,(1009, 2, 'Microsoft FOR MAT', 'MAT', NULL, 0)
,(1010, 3, 'Apple', 'MAT', NULL, 1)
,(1011, 4, 'Wikipedia FOR MAT', 'MAT', NULL, 0)
,(1012, 1, 'Whosebug', NULL, 'JEAN', 1)
,(1013, 2, 'Microsoft ', NULL, 'JEAN', 0)
,(1014, 3, 'Apple', NULL, 'JEAN', 0)
,(1015, 4, 'great encyclopedia', NULL, 'JEAN', 0)
;
SELECT t2.* ,t1.URLName
FROM @TABLE1 t1
INNER JOIN @TABLE2 t2 ON t1.URL_ID = t2.URL_ID
WHERE EXISTS (
SELECT 1
FROM (
SELECT TOP (1) test.PREF_ID
,CASE
-- if I do not comment this case: jean from the MAT group will not see apple
-- WHEN Hide_Url = 1
-- THEN 3
WHEN USER_code IS NOT NULL
THEN 2
WHEN USER_GROUP IS NOT NULL
THEN 1
ELSE 0
END AS ROW_LEVEL
FROM @TABLE2 test
WHERE (
(
test.USER_GROUP IS NULL
AND test.user_group IS NULL
AND test.USER_code IS NULL
)
OR (test.USER_GROUP = @CUR_GROUP)
OR (test.USER_code = @CUR_USER)
)
AND t2.URL_ID = test.URL_ID
ORDER BY ROW_LEVEL DESC
) test
WHERE test.PREF_ID = t2.PREF_ID
AND Hide_Url = 0
)
只需使用 ORDER BY
子句,将首选行放在首位。您可以在 window 函数 ROW_NUMBER
中使用它并使用它或使用横向 top(1) 加入 CROSS APPLY
.
select *
from urls
cross apply
(
select top(1) *
from labels
where labels.url_id = urls.url_id
where [Group] is not null or [user] is not null or hide is not null
order by
case when [Group] is null then 2 else 1 end,
case when [user] is null then 2 else 1 end,
case when hide is null then 2 else 1 end
) top_labels
order by urls.url_id;
你好,如果可能的话,我想找到一个解决方案来解决我的问题。 现在我把所有的记录都拿出来,然后我一条一条地检查那些我不想要的东西。
我有 2 个 table:第一个 table 有链接
第二个带有 url
的首选标签必须查询第二个 table,只保留具有最高优先级的行
优先规则是 当前用户然后 用户组,最后 大家
如果隐藏列为真,则排除对 url
的任何引用这是预期的结果。
不幸的是,除了将条件乘以多个选择和联合之外,我看不到任何其他解决方案。
如果您有解决我问题的想法,在此先感谢您的帮助
您似乎可以依靠 pref_id
进行偏好排序,对吗?如果是这样,你可以试试:
SELECT *
FROM table2
INNER JOIN table1 ON table2.url_id = table1.url_id
QUALIFY ROW_NUMBER() OVER (
PARTITION BY table1.url
ORDER BY pref_id ASC
) = 1
这将按 url 进行分区,然后仅提供 pref_id 最低的那个。
我没有测试这个 SQL 因为我不确定你 运行 在哪个 RDBMS 上,但我使用 Rasgo 来翻译 SQL .
可能对这个棘手的查询感兴趣:
select so.*, table1.url from
(select distinct t.url_id,
(select pref_id from table2 s where s.url_id = t.url_id order by "user" is null, "group" is null limit 1) pref_id
from table2 t
where not exists(select 1 from table2 s where s.hide and s.url_id = t.url_id)
) ids
join table2 so on so.pref_id = ids.pref_id
join table1 ON table1.url_id = ids.url_id
order by so.url_id;
这是我的解决方案,但我认为还有更好的办法。
在条件的select中,我建立了一个列,根据优先级
给出了级别注释DECLARE @CUR_USER VARCHAR(10) = 'ROBERT'
DECLARE @CUR_GROUP VARCHAR(10) = 'DEV'
DECLARE @TABLE1 TABLE (
URL_ID INT
,URLNAME VARCHAR(100)
);
DECLARE @TABLE2 TABLE (
PREF_ID INT
,URL_ID INT
,FAVORITE_LABEL VARCHAR(100)
,USER_GROUP VARCHAR(10)
,USER_CODE VARCHAR(10)
,HIDE_URL DECIMAL(1, 0) DEFAULT 0
);
INSERT INTO @TABLE1
VALUES
(1, 'https://whosebug.com/')
,(2, 'https://www.microsoft.com/')
,(3, 'https://www.apple.com/')
,(4, 'https://www.wikipedia.org/')
;
INSERT INTO @TABLE2
VALUES
(1000, 1, 'find everything', NULL, 'ROBERT', 0)
,(1001, 1, 'a question ? find the answer here', 'DEV', NULL, 0)
,(1002, 1, 'Whosebug', NULL, NULL, 0)
,(1003, 2, 'Windows', 'DEV', NULL, 0)
,(1004, 2, 'Microsoft', NULL, NULL, 0)
,(1005, 3, 'Apple', NULL, NULL, 0)
,(1006, 4, 'Free encyclopedia', NULL, 'ROBERT', 1)
,(1007, 4, 'Wikipedia', NULL, NULL, 0)
,(1008, 1, 'Whosebug FOR MAT', 'MAT', NULL, 0)
,(1009, 2, 'Microsoft FOR MAT', 'MAT', NULL, 0)
,(1010, 3, 'Apple', 'MAT', NULL, 1)
,(1011, 4, 'Wikipedia FOR MAT', 'MAT', NULL, 0)
,(1012, 1, 'Whosebug', NULL, 'JEAN', 1)
,(1013, 2, 'Microsoft ', NULL, 'JEAN', 0)
,(1014, 3, 'Apple', NULL, 'JEAN', 0)
,(1015, 4, 'great encyclopedia', NULL, 'JEAN', 0)
;
SELECT t2.* ,t1.URLName
FROM @TABLE1 t1
INNER JOIN @TABLE2 t2 ON t1.URL_ID = t2.URL_ID
WHERE EXISTS (
SELECT 1
FROM (
SELECT TOP (1) test.PREF_ID
,CASE
-- if I do not comment this case: jean from the MAT group will not see apple
-- WHEN Hide_Url = 1
-- THEN 3
WHEN USER_code IS NOT NULL
THEN 2
WHEN USER_GROUP IS NOT NULL
THEN 1
ELSE 0
END AS ROW_LEVEL
FROM @TABLE2 test
WHERE (
(
test.USER_GROUP IS NULL
AND test.user_group IS NULL
AND test.USER_code IS NULL
)
OR (test.USER_GROUP = @CUR_GROUP)
OR (test.USER_code = @CUR_USER)
)
AND t2.URL_ID = test.URL_ID
ORDER BY ROW_LEVEL DESC
) test
WHERE test.PREF_ID = t2.PREF_ID
AND Hide_Url = 0
)
只需使用 ORDER BY
子句,将首选行放在首位。您可以在 window 函数 ROW_NUMBER
中使用它并使用它或使用横向 top(1) 加入 CROSS APPLY
.
select *
from urls
cross apply
(
select top(1) *
from labels
where labels.url_id = urls.url_id
where [Group] is not null or [user] is not null or hide is not null
order by
case when [Group] is null then 2 else 1 end,
case when [user] is null then 2 else 1 end,
case when hide is null then 2 else 1 end
) top_labels
order by urls.url_id;