部分字符串上的SQL连接会产生太多子记录中带有max的记录

时间:2017-06-12 16:15:13

标签: sql sql-server

我有一个包含4个char错误代码的表及其描述。 我在一个字符串中有一个销售表,其中包含多个错误代码。 我设计了一个使用类似的连接,允许加入最高加权的错误代码,除非2个或更多错误具有相同的权重,这会创建多个连接的行,这样就可以正常工作。

如果权重相等,我只想要1个结果(任何会做)

TABLE ErrorCodes

Code   | Description       | Weight
'0041' | 'data error'      | 4
'0019' | 'format error'    | 2
'0099' | 'missing creator' | 2

TABLE MyData

ID   | RespCode     
1234 | '00410019'
1235 | '00990019'

结果我

ID   | RespCode   | Description
1234 | '00410019' | 'data error' 
1235 | '00990019' | 'format error'
1235 | '00990019' | 'missing creator'

我只想要1235的1个结果,但即使在子选择中使用Max或Top 1,我也得到2个。我怎样才能限制为1个连接的行?

    SELECT * FROM MyData 
    left JOIN ErrorCodes
    ON     MyData.RespCode 
    LIKE '%' + ErrorCodes.Code + '%' 
    AND ErrorCodes.Weight = ( 
        SELECT MAX (Weight) FROM ErrorCodes 
        WHERE  MyDate.RespCode LIKE '%' + ErrorCodes.Code + '%' 
    ) 

3 个答案:

答案 0 :(得分:1)

Window Functions to the rescue! :-)

SELECT ec2.ID, ec2.RespCode, ec2.[Description] 
FROM (
    SELECT ec1.ID, ec1.RespCode, ec1.Code, ec1.[Description], ec1.[Weight] , ROW_NUMBER() OVER ( PARTITION BY ec1.ID ORDER BY ec1.[Weight] ASC ) AS rn 
    FROM (
        SELECT 
              md.id
            , md.RespCode
            , ec.Code
            , ec.[Description]
            , ec.[Weight]

        FROM #myData md
        LEFT OUTER JOIN #ErrorCodes ec ON md.RespCode LIKE '%' + ec.Code + '%' 
    ) ec1
) ec2
WHERE ec2.rn = 1

答案 1 :(得分:1)

SELECT
  ID, RespCode, Description
FROM
(
  SELECT
    ID,
    RespCode,
    Description,
    ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Weight DESC) as rown
  FROM 
    MyData 
    LEFT JOIN 
    ErrorCodes
    ON
      MyData.RespCode LIKE '%' + ErrorCodes.Code + '%' 
) a
WHERE
  rown = 1

Need a recent version of SQLS (2008+) for this. You take your query with all the duplicated row ids, and you ask SQLserver to do an in-place aggregating (partition by) and row numbering; it will give a counter that counts 1, 2, 3, etc for each ID, the counter restarts upon a change of ID (thanks to partition by), and the rows it counts are ordered by weight descending (higher weight comes first

Then we just select only rows where the counter is 1

To see what I mean about the inner query, just highlight that one between the brackets and run it, to see the ROWN column and how it behaves

Note: I see that Shawn's query is more or less same (Sorry Shawn, only looked closely at your query after I wrote mine, because the windowing function was off screen due to long lines), only has an extra unneeded subquery, and also his partiton/order by clause is wrong (it selects the lowest weighted weight thanks to ASC, you wanted highest weight to take precedence)

答案 2 :(得分:0)

使用以下查询

  SELECT * FROM MyData 
    left JOIN ErrorCodes
    ON     MyData.RespCode 
    LIKE '' + ErrorCodes.Code + '%' 
    AND ErrorCodes.Weight = ( 
        SELECT MAX (Weight) FROM ErrorCodes 
        WHERE  MyDate.RespCode LIKE '%' + ErrorCodes.Code + '%' 
    )