【问题标题】:How to get common value for two records from msSQL如何从 msSQL 获取两条记录的共同值
【发布时间】:2011-09-05 07:02:07
【问题描述】:
catId  DealId
 1      668
 2      668
 3      669
 1      669
 3      671
11      671
12      671
 7      669
12      672
13      673

假设它是一张桌子。如果我为catId 提供两个值作为输入,则查询应返回包含相同DealId 的所有记录。

【问题讨论】:

  • 如果 CatId 有多个 DealId 会发生什么 - 即,如果您将 Catid IN (1,3) 作为输入,它是否应该返回 CatIds 1,2,3,11,12?

标签: sql-server sql-server-2005


【解决方案1】:

Revision1:我添加了一个精确除法的示例

这个操作被命名为关系分割。 在这种情况下,Table1(CatID, DealID) 是被除数,Table2(CatID) 是除数。 Table1(CatID, DealID) DIVIDED BY Table2(CatID) 运算的结果(商)表示具有相同 CatID(表 2)的所有 DealID(表 1)。

我不太清楚:您需要精确除法还是带余数的除法?

看看这个由 Joe Celko 写的article

(Revision1)精确除法示例(我在 (CatID,DealID) 表中的值不同;解释和风险如下所示):

DECLARE @Table1 TABLE
(
    DealID INT NOT NULL
    ,CatID INT NOT NULL
    ,PRIMARY KEY(DealID, CatID)
);
INSERT  @Table1 (DealID, CatID)
SELECT  src.DealID, src.CatID
FROM
(
SELECT 1 CatID, 668 DealID
UNION ALL
SELECT 2 CatID, 668 DealID
UNION ALL
SELECT 2 CatID, 669 DealID
UNION ALL
SELECT 1 CatID, 669 DealID
UNION ALL
SELECT 2 CatID, 671 DealID
UNION ALL
SELECT 11 CatID, 671 DealID
UNION ALL
SELECT 12 CatID, 671 DealID
UNION ALL
SELECT 11 CatID, 672 DealID
UNION ALL
SELECT 12 CatID, 672 DealID
UNION ALL
SELECT 13 CatID, 673 DealID
) src;

--Test1
DECLARE @Table2 TABLE
(
    CatID INT NOT NULL PRIMARY KEY
);
INSERT  @Table2 
VALUES  (1);
INSERT  @Table2 
VALUES  (2);

SELECT  CatID, DealID
FROM    @Table1
ORDER BY DealID;
SELECT  *
FROM    @Table2
ORDER BY CatID;

SELECT  a.DealID--, CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(a.CatID AS VARCHAR(11)))) ) Agg
FROM    @Table1 a
GROUP BY a.DealID 
HAVING  CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(a.CatID AS VARCHAR(11)))) ) = 
(
    SELECT  CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(b.CatID AS VARCHAR(11)))) ) 
    FROM    @Table2 b
);
--End of Test1

--Test2
DELETE @Table2;
INSERT  @Table2 
VALUES  (11);
INSERT  @Table2 
VALUES  (12);

SELECT  a.DealID--, CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(a.CatID AS VARCHAR(11)))) ) Agg
FROM    @Table1 a
GROUP BY a.DealID 
HAVING  CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(a.CatID AS VARCHAR(11)))) ) = 
(
    SELECT  CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(b.CatID AS VARCHAR(11)))) ) 
    FROM    @Table2 b
);
--End of Test2

解释:

  1. 此子查询 SELECT CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(b.CatID AS VARCHAR(11)))) ) FROM @Table2 b 为除数表(表 2 b)中的所有 CatID 值生成一个标识符。
  2. 基本查询将对股息表(表 1 a)中的记录进行分组:GROUP BY a.DealID,并且对于每个 a.DealID 值,它会使用散列函数为来自 CatID 字段的所有值生成一个标识符:CHECKSUM_AGG( CHECKSUM(HASHBYTES('sha1',CAST(a.CatID AS VARCHAR(11)))) )

风险:

  1. 有时,哈希函数会产生冲突(尤其是旧的哈希函数:CHECKSUM[_AGG])。
  2. 为了降低碰撞风险,我使用 HASHBYTES 函数。
  3. 根据我的测试(不知何故,这个问题对我来说已经很老了),我从未遇到过碰撞,但从不说永远
  4. 解决方案按“原样”提供,不提供任何保证。
  5. 对于生产,请使用 Celko 解决方案之一。

【讨论】:

    【解决方案2】:

    SQL 语句

    ;WITH CatIDs (catID) AS (
        SELECT  1
        UNION ALL SELECT 2
    )   
    SELECT  mt.*
    FROM    MyTable mt
            INNER JOIN CatIDs cid ON cid.catID = mt.catID
            INNER JOIN (
                SELECT  mt.DealID
                FROM    MyTable mt
                        INNER JOIN CatIDs ids ON ids.catID = mt.catID
                GROUP BY
                        mt.DealID
                HAVING  COUNT(mt.DealID) = (SELECT COUNT(*) FROM CatIDs)
            ) did ON did.DealID = mt.DealID
    

    测试脚本

    ;WITH MyTable (catID, DealID) AS (
        SELECT 1, 668
        UNION ALL SELECT 2, 668
        UNION ALL SELECT 3, 669
        UNION ALL SELECT 1, 669
        UNION ALL SELECT 3, 671
        UNION ALL SELECT 11, 671
        UNION ALL SELECT 12, 671
        UNION ALL SELECT 7, 669
        UNION ALL SELECT 12, 672
        UNION ALL SELECT 13, 673
    )
    , CatIDs (catID) AS (
        SELECT  1
        UNION ALL SELECT 2
    )   
    SELECT  mt.*
    FROM    MyTable mt
            INNER JOIN CatIDs cid ON cid.catID = mt.catID
            INNER JOIN (
                SELECT  mt.DealID
                FROM    MyTable mt
                        INNER JOIN CatIDs ids ON ids.catID = mt.catID
                GROUP BY
                        mt.DealID
                HAVING  COUNT(mt.DealID) = (SELECT COUNT(*) FROM CatIDs)
            ) did ON did.DealID = mt.DealID
    

    【讨论】:

      【解决方案3】:

      试试这个(这就是你需要的):

      SELECT DealId, catId, count(catId) AS tot
      FROM your_table
      WHERE catId = your_cat1 OR catId = your_cat2
      GROUP BY DealId
      HAVING tot > 1
      

      【讨论】:

      • 只有当两个 catid 的交易 ID 相同时才返回查询
      • @john: HAVING tot>1 应该做这项工作。我现在无法测试它,所以我认为这可以工作,但我不确定,抱歉。
      【解决方案4】:

      我不明白你的问题,希望下面的语法对你有所帮助。 创建过程 [spName]

          @Parameter1 INT,
          @Parameter2 INT
      
      AS 
          BEGIN              
      
              SELECT * FROM TableName WHERE 
              DealId    FROM    TableName WHERE catId=@Parameter1
              AND 
              DealId    FROM    TableName WHERE catId=@Parameter2
           END
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-07
        • 1970-01-01
        • 1970-01-01
        • 2015-02-15
        • 2018-06-10
        • 2016-12-01
        相关资源
        最近更新 更多