我正在尝试创建一个查找表,其中元素的顺序很重要。我的查找表具有以下结构
id table1id table2id
1 1 1
2 1 2
3 1 3
4 2 2
5 2 1
6 2 3
我的目标是根据table2ids找到table1id。所以我运行的示例查询是
Select table1id
from junctionTable
where table2ids in (1,2,3)
group by table1id
Having count(table1id) = 3
然而,这将有效,它将返回Table1Ids 1和2.我只希望Table1ID具有特定顺序的1,2,3,因此它应该只返回TableId = 1。
在表格上放置一个订单栏,但随着项目数量的增加,查询会变得更加困难。
select table1id from junctionTable
where table2id =1 and order =1 and
table2id = 2 and order =2
etc...
还有什么我能做的,我没想到的?或者处理这种情况的最佳方法是什么?
问题源于我试图规范化表格。请参阅Normalize a table with tightly coupled data以获取参考
答案 0 :(得分:2)
以下查询可以返回您的预期结果:
WITH CTE AS (
SELECT table1id, table2id, ROW_NUMBER() OVER(PARTITION BY table1id ORDER BY id) AS CustomOrder
FROM JunctionTable
WHERE table2id IN (1, 2, 3)
)
SELECT table1id
FROM CTE
WHERE table2id = CustomOrder
GROUP BY table1id
HAVING COUNT(DISTINCT table2id) = 3
使用给定的样本数据进行演示:
DECLARE @JunctionTable TABLE (id INT, table1id INT, table2id INT);
INSERT INTO @JunctionTable (id, table1id, table2id) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 2, 2),
(5, 2, 1),
(6, 2, 3);
WITH CTE AS (
SELECT table1id, table2id, ROW_NUMBER() OVER(PARTITION BY table1id ORDER BY id) AS CustomOrder
FROM @JunctionTable
WHERE table2id IN (1, 2, 3)
)
SELECT table1id
FROM CTE
WHERE table2id = CustomOrder
GROUP BY table1id
HAVING COUNT(DISTINCT table2id) = 3
答案 1 :(得分:0)
如果顺序很重要,那么必须通过使其成为数据的属性来明确地跟踪排序。在您当前的模型中,订单被隐式存储,并且这不起作用,因为您永远不应该假设SQL存储和返回数据的顺序。
根据你问题中的基表,你可以添加一个varchar来命令“正确的”table2id排序,比如
Id table1id table2id table2order
1 1 1 1,2,3
2 1 2 1,2,3
3 1 3 1,2,3
4 2 2 2,1,3
5 2 1 2,1,3
6 2 3 2,1,3
这当然没有规范化,所以你可以选择第二个表:
table1id table2order
1 1,2,3
2 2,1,3
使用其中一个或另一个应该支持您的目标。
答案 2 :(得分:0)
select table1id
from
(
select table1id, (table2id - id) as diff
from junctionTable
where table2ids in (1,2,3)
)
group by table1id, as diff
having count(*) = 3
答案 3 :(得分:0)
为了解决这个问题,您必须创建一个查找表,该表定义了您想要使用的目标table2id的所需顺序,因为IN
子句在匹配这两个集合时不会强加订单。
如果你有SQL Server 2012或更高版本,那么你可以使用LAG
窗口函数来帮助解决问题,如下所示:
DECLARE @table2IdInOrder TABLE
(
OrderID INT IDENTITY(1,1)
,table2id INT
);
INSERT INTO @table2IdInOrder
VALUES(2), (1), (3);
WITH CTE_JT AS (
SELECT JT.id
,JT.table1id
,JT.table2id
,JT.table2id - LAG(JT.table2id, 1, 0) OVER(PARTITION BY JT.table1id ORDER BY JT.id) AS DeltaID
,COUNT(JT.table2id) OVER(PARTITION BY JT.table1id) AS RecordCount
FROM @junctionTable JT
WHERE JT.table2id IN (SELECT table2id FROM @table2IdInOrder)
)
, CTE_OT
AS
(
SELECT OT.OrderID
,OT.table2id
,OT.table2id - LAG(OT.table2id, 1, 0) OVER(ORDER BY OT.OrderID) AS DeltaID
,COUNT(OT.table2id) OVER(PARTITION BY (SELECT 1 AS ID)) AS RecordCount
FROM @table2IdInOrder OT
)
SELECT DISTINCT JT.table1id
FROM CTE_JT JT
INNER JOIN CTE_OT OT ON OT.table2id = JT.table2id AND OT.DeltaID = JT.DeltaID AND OT.RecordCount = JT.RecordCount;
答案 4 :(得分:0)
此查询检查Id和Table2Id的顺序是否相同。
WITH CTE AS (
SELECT table1id, table2id
,orderIsOK = ROW_NUMBER() OVER(PARTITION BY table1id ORDER BY id)
- ROW_NUMBER() OVER(PARTITION BY table1id ORDER BY table2id)
FROM JunctionTable
WHERE table2id IN (1, 2, 3)
)
SELECT table1id
FROM CTE
WHERE orderIsOK = 0
GROUP BY table1id
HAVING COUNT(DISTINCT table2id) = 3
或者,您可能希望明确指定所需的顺序。在下面的示例中,所需的顺序指定为(2,1,3)
WITH desiredOrder(rowNumber, value) as (
select *
from (
values (1,2)
,(2,1)
,(3,3)
) t (rowNumber, value)
),
CTE AS (
SELECT table1id, table2id
,orderIsOK = ROW_NUMBER() OVER(PARTITION BY table1id ORDER BY id)
- do.rowNumber
FROM @JunctionTable t
JOIN desiredOrder do ON t.table2id = do.value
)
SELECT table1id
FROM CTE
WHERE orderIsOK=0
GROUP BY table1id
HAVING COUNT(DISTINCT table2id) = 3