选择两列中具有唯一值的行

时间:2018-10-02 16:32:03

标签: sql-server

我有一张这样的桌子:

id          col1 col2        
----------- ---- ----------- 
1           A    5
2           A    6
3           B    5
4           B    6
5           B    7
6           C    6
7           D    7

我需要选择不超过一行的任何确切值col1col2。 例如,一种可能的解决方案是:

id          col1 col2        
----------- ---- ----------- 
1           A    5
4           B    6
7           D    7

其他可能的解决方案是:

id          col1 col2        
----------- ---- ----------- 
3           B    5
6           C    6
7           D    7

我需要找到任何可能的解决方案之一。

算法非常简单:

  1. 将表中的任何行获取到输出中。
  2. 从表中排除所有行 其col1中的值等于col1或中的值 col2等于所选行中col2的值。
  3. 如果表不为空,请转到步骤1。

如何在SQL SELECT语句中实现此逻辑?

生成测试表的代码:

CREATE TABLE #t (id INT IDENTITY, col1 CHAR(1), col2 INT) ;

INSERT  INTO #t (col1, col2)
VALUES  
    ('A', 5),
    ('A', 6),
    ('B', 5),
    ('B', 6),
    ('B', 7),
    ('C', 6),
    ('D', 7);

4 个答案:

答案 0 :(得分:2)

SELECT  id, col1, col2
FROM    ( SELECT    * ,
                    ROW_NUMBER() OVER ( PARTITION BY col2 ORDER BY col2 ) Row#
          FROM      #t
        ) x
WHERE   x.Row# = 1

答案 1 :(得分:0)

使用光标尝试以下操作:

create table #final (id int, col1 varchar(10), col2 int)

declare @id int, @col1 varchar(10), @col2 int
declare cur cursor for select id, col1, col2 from #t order by newid()

open cur
fetch next from cur into @id, @col1, @col2
while @@FETCH_STATUS = 0
begin
    if (@col1 in (select col1 from #final) or @col2 in (select col2 from #final))
    begin
        fetch next from cur into @id, @col1, @col2
        continue
    end
    insert into #final
    select id, @col1, @col2 from #t where col1 = @col1 and col2 = @col2 and id = @id
    fetch next from cur into @id, @col1, @col2
end

close cur
deallocate cur

select * from #final order by id

drop table #final

结果:

Run_result

答案 2 :(得分:0)

这不是通过直接SQL解决的简单方法。我想我会使用递归CTE来破解它。这会吐出所有可能的组合,但是……在这里称为“路径”的字段中。也许它将提出直接使用tsql的方法。

With recCTE AS
(
    SELECT 
      col1, 
      col2, 
      0 as depth, 
      CAST(col1 + '|' + CAST(col2 AS varchar(10)) AS VARCHAR(30)) as path 
    FROM t

    UNION ALL

    SELECT       
      t1.col1, 
      t1.col2, 
      rec.depth + 1, 
      CAST(rec.path + '>' + t1.col1 + '|' + cast(t1.col2 as varchar(10)) as varchar(30))
    FROM t t1
        INNER JOIN recCTE rec
        ON rec.path NOT LIKE '%|' + CAST(t1.col2 as varchar(10)) + '%'
           AND rec.path NOT LIKE '%' + CAST(t1.col2 as varchar(10)) + '|%'
    WHERE depth + 1 <= 3 

)
SELECT * 
FROM recCTE 
WHERE depth = 2

答案 3 :(得分:0)

尝试此查询:

SELECT  id, col1, col2
FROM ( SELECT    * ,
       RANK() OVER ( PARTITION BY col2 ORDER BY col2 ) Row#
       FROM      #t
     ) x
WHERE   x.Row# = 1