消除结果中的重复组合

时间:2013-11-28 22:46:36

标签: sql sql-server

我有一个像这样的选择结果:

from_loc    | to_loc   |
-------------------------
 A          |  B
------------------------
 B          |  C
------------------------
 B          |  A
------------------------  

如何消除表中的重复项,这意味着 A到B B到A 的出现意味着重复。

我正在尝试创建这样的结果,在尝试了几种方法之后我无法解决这个问题......

from_loc    | to_loc   |
-------------------------
 A          |  B
------------------------
 B          |  C
------------------------

任何人都可以给我一些提示或参考,我怎样才能达到这种效果?

4 个答案:

答案 0 :(得分:2)

我没有测试过这个解决方案,但它可以有更好的性能(更少的逻辑读取):

DECLARE @MyTable TABLE
(
    from_loc VARCHAR(100) NOT NULL,
    to_loc   VARCHAR(100) NOT NULL
);
INSERT  @MyTable (from_loc, to_loc) VALUES  ('A', 'B');
INSERT  @MyTable (from_loc, to_loc) VALUES  ('B', 'C');
INSERT  @MyTable (from_loc, to_loc) VALUES  ('B', 'A');

SELECT  DISTINCT src.from_loc_new, src.to_loc_new
FROM
(
SELECT  CASE WHEN x.from_loc <= x.to_loc THEN x.from_loc ELSE x.to_loc END AS from_loc_new,
        CASE WHEN x.from_loc <= x.to_loc THEN x.to_loc ELSE x.from_loc END AS to_loc_new
FROM    @MyTable x
) src
-- You could also test these query hints to see if there is a better performance
-- OPTION (HASH GROUP) 
-- or 
-- OPTION (ORDER GROUP);

答案 1 :(得分:1)

也许CASE中有ROW_NUMBER

WITH CTE AS( 
  SELECT from_loc, to_loc, 
         rn = row_Number() Over (Partition By  CASE WHEN from_loc > to_loc
                                    Then to_loc + '|' + from_loc 
                                    Else from_loc + '|' + to_loc END
                                 Order By from_loc, to_loc)
  FROM dbo.TableName
)
SELECT from_loc, to_loc FROM cte WHERE rn = 1

Demo

答案 2 :(得分:0)

尝试DISTINCT然后NOT EXISTS,例如:

SELECT DISTINCT from_loc, to_loc
FROM TableName A
WHERE NOT EXISTS
(
  SELECT from_loc, to_loc
  FROM TableName B
  WHERE A.from_loc = B.to_loc
  AND A.to_loc = B.from_loc
 )

DISTINCT将消除重复from_loc-->from_locto_loc--->to_loc 虽然NOT EXISTS会消除重复的from_loc-->to_locto_loc-->from_loc

答案 3 :(得分:0)

假设您的原始SQL是:

SELECT from_loc, to_loc FROM route;

使用它作为与LEFT JOIN连接在一起的子查询两次。之后,使用IF明确选择所需的字段。

SELECT DISTINCT
  IF (y.from_loc IS NULL, x.from_loc,
    IF(x.from_loc < x.to_loc, x.from_loc, x.to_loc)) AS from_loc,
  IF (y.from_loc IS NULL, x.to_loc,
    IF(x.from_loc > x.to_loc, x.from_loc, x.to_loc)) AS to_loc
FROM (
) AS x
  SELECT from_loc, to_loc FROM route
LEFT JOIN (
  SELECT from_loc, to_loc FROM route
) AS y
ON x.from_loc = y.to_loc AND x.to_loc = y.from_loc;

对于演示,我使用以下SQL在您的问题中创建示例数据:

SELECT "A" AS from_loc, "B" AS to_loc
UNION SELECT "B", "C"
UNION SELECT "B", "A";

在MySQL客户端应用程序上试试这个:

SELECT DISTINCT
  IF (y.from_loc IS NULL, x.from_loc,
    IF(x.from_loc < x.to_loc, x.from_loc, x.to_loc)) AS from_loc,
  IF (y.from_loc IS NULL, x.to_loc,
    IF(x.from_loc > x.to_loc, x.from_loc, x.to_loc)) AS to_loc
FROM (
) AS x
  SELECT "A" AS from_loc, "B" AS to_loc
  UNION SELECT "B", "C"
  UNION SELECT "B", "A"
LEFT JOIN (
  SELECT "A" AS from_loc, "B" AS to_loc
  UNION SELECT "B", "C"
  UNION SELECT "B", "A"
) AS y
ON x.from_loc = y.to_loc AND x.to_loc = y.from_loc;

我知道这不是一个有效的解决方案,但它只是有效!