【问题标题】:How do I get 'matched' and 'unmatched' rows from a single table如何从单个表中获取“匹配”和“不匹配”行
【发布时间】:2018-04-18 03:18:37
【问题描述】:

我想让两个存储过程分别从一个表中获取“匹配”和“不匹配”行...

“匹配”行是状态分别为 1 和 2 的两行,对于相同的:

uID aID cID and pID

“不匹配”行是状态为 1 的行,但不存在状态为 2 且具有相同 uID、aID、cID 和 pID 的行

(为简洁起见,我从数据中删除了唯一标识符 Indx)

样本数据

uID aID cID pID state   occurs
10  200 5000    1240    1   2018-04-17 08:12:13.367
80  542 9000    5700    1   2018-04-17 08:12:54.113
10  240 5000    3860    1   2018-04-17 08:13:09.817
10  200 5000    1240    2   2018-04-17 08:13:18.010
30  240 7000    5938    1   2018-04-17 08:13:31.510
80  542 9000    5700    2   2018-04-17 08:14:04.363

以下是“匹配”行的示例

uID aID cID pID state   occurs
10  200 5000    1240    1   2018-04-17 08:12:13.367
10  200 5000    1240    2   2018-04-17 08:13:18.010
80  542 9000    5700    1   2018-04-17 08:12:54.113
80  542 9000    5700    2   2018-04-17 08:14:04.363

以下是“不匹配”行的示例

uID aID cID pID state   occurs
10  240 5000    3860    1   2018-04-17 08:13:09.817
30  240 7000    5938    1   2018-04-17 08:13:31.510

匹配的行代码

我遇到困难的地方是围绕将匹配集分组的语句......我想我可以做这样的事情来获得1和2的两行但没有这样的运气......

select uID, aID, cID, pID, state
from Data where state in (1,2) 
group by uID, aID, cID, pID, state
having state = 2 and state = 1

不匹配的行代码

然后我想我可以对不匹配的行做类似的事情,但这也不起作用....

select uID, aID, cID, pID, state
from Data where state in (1,2) 
group by uID, aID, cID, pID, state
having state != 2 and state = 1

我需要一些帮助...谢谢

基础设施

创建表格的代码如下:

CREATE TABLE [dbo].[Data](
    [INDX] [uniqueidentifier] NOT NULL,
    [uID] [int] NOT NULL,
    [aID] [int] NOT NULL,
    [cID] [int] NOT NULL,
    [pID] [int] NOT NULL,
    [state] [int] NOT NULL,
    [occurs] [datetime] NOT NULL,
 CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED 
(
    [INDX] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

“插入数据”的存储过程

CREATE PROCEDURE [dbo].[InsertData]
    -- Add the parameters for the stored procedure here

    @userID int, 
    @appID int, 
    @compID int, 
    @procID int, 
    @state int,
    @occurence datetime

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here

        declare @indx as uniqueidentifier
        set @indx = NEWID();

        insert into [Data]
        Values(
                @indx,
                @userID,
                @appID,
                @compID,
                @procID,
                @state,
                @occurence
                )

END
GO

这里有一些代码可以帮助填充表格:

declare @userID int
declare @appID int
declare @compID int
declare @procID int
declare @state int
declare @occurence datetime

set @userID = 10
set @appID = 200
set @compID = 5000
set @procID = 1240
set @state = 1

set @occurence = GETDATE();
EXEC InsertData @userID, @appID, @compID, @procID, @state, @occurence

添加其他状态时进行测试:

    set @userID = 80
    set @appID = 546
    set @compID = 9000
    set @procID = 5700
    set @state = 3
    set @occurence = GETDATE();
    EXEC InsertData @userID, @appID, @compID, @procID, @state, @occurence

所以我最终得到了这个数据集:

uID aID cID pID state
10  200 5000    1240    2
10  200 5000    1240    1
10  240 5000    3860    1
80  542 9000    5700    1
30  240 7000    5938    1
80  546 9000    5700    3
80  542 9000    5700    2

所以...scsimon...您的查询效果很好...但是如果是这种情况怎么办:

添加了新的重复数据

uID aID cID pID state
10  200 5000    1240    1
80  542 9000    5700    1
10  240 5000    3860    1
10  200 5000    1240    2
30  240 7000    5938    1
80  542 9000    5700    2
80  546 9000    4502    3
10  200 5000    1240    1
10  200 5000    1240    2

查询结果,接近了……

uID aID cID pID state   occurs
10  200 5000    1240    1   2018-04-17 11:57:22.693
10  200 5000    1240    1   2018-04-17 11:57:29.797
10  200 5000    1240    2   2018-04-17 11:57:25.740
10  200 5000    1240    2   2018-04-17 11:57:30.827
80  542 9000    5700    1   2018-04-17 11:57:23.710
80  542 9000    5700    2   2018-04-17 11:57:27.767

但我真正想要的是:

uID aID cID pID state   occurs
10  200 5000    1240    1   2018-04-17 11:57:22.693
10  200 5000    1240    2   2018-04-17 11:57:25.740

10  200 5000    1240    1   2018-04-17 11:57:29.797
10  200 5000    1240    2   2018-04-17 11:57:30.827

80  542 9000    5700    1   2018-04-17 11:57:23.710
80  542 9000    5700    2   2018-04-17 11:57:27.767

最终答案(感谢 scsimon)

'匹配'

select t.uID, t.aID, t.cID, t.pID, t.state, t.occurs
from Data t
inner join
    (select uID, aID, cID, pID
     from Data
     where state in (1,2) --optional if needed
     group by uID, aID, cID, pID
     having count(*) > 1) t2 on 
 t2.uID = t.uID
 and t2.aID = t.aID
 and t2.cID = t.cID
 and t2.pID = t.pID
 order by uID, occurs, state

返回一组:

uID aID cID pID state   occurs
10  200 5000    1240    1   2018-04-17 11:57:22.693
10  200 5000    1240    2   2018-04-17 11:57:25.740
10  200 5000    1240    1   2018-04-17 11:57:29.797
10  200 5000    1240    2   2018-04-17 11:57:30.827
80  542 9000    5700    1   2018-04-17 11:57:23.710
80  542 9000    5700    2   2018-04-17 11:57:27.767

'不匹配'

select t.uID, t.aID, t.cID, t.pID, t.state, t.occurs
from Data t
inner join
    (select uID, aID, cID, pID
     from Data
     where state in (1,2) --optional if needed
     group by uID, aID, cID, pID
     having count(*) = 1) t2 on 
 t2.uID = t.uID
 and t2.aID = t.aID
 and t2.cID = t.cID
 and t2.pID = t.pID
 order by occurs

返回一个集合:

uID aID cID pID state   occurs
10  240 5000    3860    1   2018-04-17 11:57:24.727
30  240 7000    5938    1   2018-04-17 11:57:26.753

【问题讨论】:

  • 在这里想想你的 where 谓词。您要求 state = 1 AND state = 2 的行。单行不能有超过 1 个值,因此这将永远不会返回任何行。但是由于您将它们分组,您可以使用 count(*) = 2 来获得两者。并且不确定你在用 2 和 = 1 做什么。这很奇怪。

标签: sql-server stored-procedures


【解决方案1】:

假设uID, aID, cID, pID 的每个唯一耦合只会处于这些状态一次,您可以使用它。

--matching rows
select t.*
from table t
inner join
    (select uID, aID, ,cID, pID
     from table
     where state in (1,2) --optional if needed
     group by uID, aID, cID, pID
     having count(*) > 1) t2 on 
 t2.uID = t.uID
 and t2.aID = t.aID
 and t2.cID = t.cID
 and t2.pID = t.pID


 --unmatching rows
select t.*
from table t
inner join
    (select uID, aID, ,cID, pID
     from table
     where state in (1,2) --optional if needed
     group by uID, aID, cID, pID
     having count(*) = 1) t2 on 
 t2.uID = t.uID
 and t2.aID = t.aID
 and t2.cID = t.cID
 and t2.pID = t.pID

【讨论】:

  • 所以...我选择添加另一个不相关的状态...例如 state = 3.... 它仍然有效!
  • stackoverflow.com/users/6167855/scsimon : 如果我有多条相同的记录呢? (见更新的问题)
  • 我不明白接下来的问题。看来您只需要在查询底部应用order by uID, aID, cID, pID, state, occurs
  • 检查最后一个重复数据添加样本中的状态...它是 1,1,2,2,1,2 而不是 1,2,1,2,1,2
  • 但是如果你添加我上面提到的订单,会发生什么?
【解决方案2】:

我能够使用 existsnot exists 复制您的预期输出

--Matched row code
SELECT * 
  FROM Data D1
 WHERE EXISTS (SELECT *
                 FROM Data D2
                WHERE D2.uID = D1.uID AND D2.aID = D1.aID AND D2.cID = D1.cID
                  AND D2.state = 2)
ORDER BY uID, state

--Unmatched row code    
SELECT * 
  FROM Data D1
 WHERE NOT EXISTS (SELECT *
                     FROM Data D2
                    WHERE D2.uID = D1.uID AND D2.aID = D1.aID AND D2.cID = D1.cID
                      AND D2.state = 2)
ORDER BY uID, state

【讨论】:

  • 所以...我选择添加另一个不相关的状态...例如state = 3...。它不起作用。
  • 问题中没有明确说明状态多于 1 和 2 的事实。您可以尝试D2.state IN (2,3)。或D2.state != 1。它可能会满足您的需求。
【解决方案3】:

这个怎么样。我假设这里只有 2 个状态 1 和 2。

SELECT  a.*
FROM    Data a
  JOIN (SELECT uID, aID, cID, pID, Count(*) as NumMatches
        FROM   Data
        Group By uID, aID, cID, pID
        Having Count(*) = 2) b ON a.uID = b.uID and a.aID = b.aID and a.cID = b.cID and a.pID = b.pID
Order by a.uID, a.aID, a.cID, a.pID 

对于不匹配

SELECT  a.*
FROM    Data a
  LEFT OUTER JOIN (SELECT uID, aID, cID, pID, Count(*) as NumMatches
        FROM   Data
        Group By uID, aID, cID, pID
        Having Count(*) = 2) b ON a.uID = b.uID and a.aID = b.aID and a.cID = b.cID and a.pID = b.pID
WHERE IsNull(b.uID,0) = 0
Order by a.uID, a.aID, a.cID, a.pID   

【讨论】:

  • 所以...我选择添加另一个不相关的状态...例如state = 3...。它不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-08
相关资源
最近更新 更多