SQL:比较列的完全匹配

时间:2015-04-15 18:38:07

标签: sql sql-server tsql analytics ssms

我有一个看起来像这样的表:

RN    ID1     ID2     Name            Source
1   W76544  945297  1_W_HO          HO
2   W76544  945297  1_W_INT         Int
1   W76547  945299  3_W_HO          HO
2   W76547  945678  3_W_INT         Int
1   W76561  NULL    Dev_U_W         AD
2   W76561  207283  Dev_W_HO        HO
3   W76561  207283  Dev_W_INT       Int
1   W76562  207284  Dev_R_HO        HO
2   W76562  207284  Dev_R_INT       Int
3   W76562  NULL    Dev_U_R         AD
1   W76563  NULL    Prd_U_W         AD
2   W76563  NULL    Prd_W_HO        HO
3   W76563  NULL    Prd_W_INT       Int

我试图找出如何确定ID1和ID2集之间的完全匹配。例如,这个例子是完全匹配的:

RN    ID1     ID2     Name            Source
1   *W76544 945297* 1_W_HO          HO
2   *W76544 945297* 1_W_INT         Int

我希望结果如下:

RN    ID1     ID2  Matched   Name            Source
1   W76544  945297   Yes    1_W_HO          HO
2   W76544  945297   Yes    1_W_INT         Int
1   W76547  945299   No     3_W_HO          HO
2   W76547  945678   No     3_W_INT         Int
1   W76561  NULL     No     Dev_U_W         AD
2   W76561  207283   No     Dev_W_HO        HO
3   W76561  207283   No     Dev_W_INT       Int
1   W76562  207284   No     Dev_R_HO        HO
2   W76562  207284   No     Dev_R_INT       Int
3   W76562  NULL     No     Dev_U_R         AD
1   W76563  NULL     Empty  Prd_U_W         AD
2   W76563  NULL     Empty  Prd_W_HO        HO
3   W76563  NULL     Empty  Prd_W_INT       Int

要声明......匹配='是'当具有相同ID1的所有组与所有具有相同ID2的组匹配时。匹配='否'当具有相同ID1的群组都不匹配ID2或某些ID1的匹配但该群组中的其他群组完全不匹配ID2时。匹配='清空'当所有具有相同ID1的组根本不匹配ID2时。

P.S。 RN是row_number,由ID1

分区并排序

感谢!!!


@BaconBits,这似乎落在你的查询中:

1   W10151820   NULL    No  DEV_U_W         AD
2   W10151820   212405  Yes DEV_W_HO    HO
3   W10151820   212405  Yes DEV_W_INTL  Int

5 个答案:

答案 0 :(得分:3)

你能做这样的事吗:

SELECT m.RN,
    m.ID1,
    m.ID2,
    CASE WHEN NOT EXISTS (SELECT 1 FROM MyTable WHERE ID1 = m.ID1 AND ID2 IS NOT NULL) THEN 'Empty'
        ELSE CASE WHEN COUNT(*) OVER(PARTITION BY m.ID1, m.ID2) > 1 THEN 'Yes' 
                ELSE 'No'
            END
    END "Matched",
    m.Name,
    m.Source
FROM MyTable m

丑陋的罪,但我认为这应该有用。

答案 1 :(得分:3)

试试这个:

Create table t(id int, c char(1))

Insert into t values
(1, 'a'),
(1, 'a'),
(2, 'b'),
(2, null),
(3, null),
(3, null),
(4, 'c'),
(4, 'd')

;with cte as(
select id, count(*) c1, count(c) c2, count(distinct c) c3 from t
group by id)
select t.id, t.c, ca.m from t
Cross apply(select case when c2 = 0 and c3 = 0 then 'empty'
            when c1 = c2 and c3 = 1 then 'yes'
            else 'no' end as m
            from cte where cte.id = t.id) ca

输出:

id  c       m
1   a       yes
1   a       yes
2   b       no
2   (null)  no
3   (null)  empty
3   (null)  empty
4   c       no
4   d       no

答案 2 :(得分:2)

为了保持清洁,轻松和易于理解,我会使用CTE来计算Matched参数。

然后我会一起加入结果。

工作示例:link

with CTE_CheckID as ( Select ID1,  [Matched] = 
CASE WHEN count(distinct ID2) = 1 AND count(distinct coalesce(id2, id1)) = 1 THEN 'Yes' ELSE
CASE WHEN count(distinct ID2) = 0 AND count(distinct coalesce(id2, id1)) = 1 THEN 'Empty' ELSE 'No' END END
FROM TABLE1
group by ID1 )

select t1.RN, 
  t1.ID1, 
  t1.ID2, 
  cID.Matched,
  t1.name,
  t1.Source
from table1 t1
left join CTE_CheckID cID on t1.ID1 = cID.ID1 

答案 3 :(得分:2)

这个怎么样?您可以在更换“YourTableNameHere”之后尝试吗?用你的表名?

WITH
  A AS (
    SELECT
      X.ID1, X.ID2,
      COUNT(1) AS Hits
    FROM YourTableNameHere X
    GROUP BY X.ID1, X.ID2
    HAVING COUNT(1) > 1
  ),
  B AS (
    SELECT
      X.ID1,
      SUM(CASE WHEN X.ID2 IS NULL THEN 0 ELSE 1 END) AS Hits,
      SUM(CASE WHEN X.ID2 IS NULL THEN 1 ELSE 0 END) AS Nulls
    FROM YourTableNameHere X
    GROUP BY X.ID1
    HAVING COUNT(1) > 1
  )
SELECT
  X.RN, X.ID1, X.ID2,
  CASE
    WHEN A.Hits = B.Nulls THEN 'Empty'
    WHEN A.Hits = B.Hits + B.Nulls THEN 'Yes'
    ELSE 'No'
  END AS [Matched],
  X.[Name], X.[Source]
FROM
  YourTableNameHere X
  LEFT JOIN A
    ON
      A.ID1 = X.ID1
      AND (A.ID2 = X.ID2 OR (A.ID2 IS NULL AND X.ID2 IS NULL))
  LEFT JOIN B ON B.ID1 = X.ID1 ;

答案 4 :(得分:1)

我认为使用分析函数可能会更容易:

select id1, id2,
       (case when cnt_1 = cnt2 and min_1_2 = max_1_2 and min_2_1 = max_2_1 and
                  cnt_1 = cnt_2_notnull
             then 'Yes'
             when cnt_2_notnull > 0
             then 'No'
             else 'Empty'
        end) as flag
from (select t.id1, t.id2,
             count(id1) over (partition by id2) as cnt_2_notnull,
             count(*) over (partition by id1) as cnt_1,
             count(*) over (partition by id2) as cnt_2,
             min(id1) over (partition by id2) as min_1_2,
             max(id1) over (partition by id2) as max_1_2,
             min(id2) over (partition by id1) as min_2_1,
             max(id2) over (partition by id1) as max_2_1
      from table t
     ) t;

逻辑是计算每个维度(id1id2)的值的数量,并比较每个维度的最小值和最大值。