我正在使用MS SQL Server Management Studio。我有桌子 -
+--------+----------+
| Num_ID | Alpha_ID |
+--------+----------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | B |
| 2 | C |
| 3 | A |
| 4 | C |
| 5 | A |
| 5 | B |
+--------+----------+
我想创建另一个包含此表中2列的表,以便column_1在Num_ID中给出唯一值(即1,2,3,4等),而column_2在Alpha_ID中给出唯一值(A,B,C和等等)。
但如果已经发生了字母表,则不应该再次出现。所以输出将是这样的 -
Col_1 Col_2
================
1 - A
----------------
2 - B
----------------
3 - NULL (as A has been chosen by 1, it cannot occur next to 3)
----------------
4 - C
----------------
5 - NULL (both 5 A and 5 B cannot be chosen as A and B were picked up by 1 and 2)
----------------
希望这是有道理的。 我想澄清一下,输入表中的ID不是我所示的数字,但Num_ID和Alpha_ID都是复杂的字符串。为了这个问题,我把它们简化为1,2,3,......和A,B,C ....
答案 0 :(得分:2)
我认为没有游标就可以做到这一点。 我在您的示例数据中添加了更多行,以测试它如何与其他案例一起使用。
逻辑是直截了当的。首先获取Num_ID
的所有不同值的列表。然后遍历它们并在每次迭代时向目标表添加一行。要确定要添加的Alpha_ID
值,我将使用EXCEPT
运算符从源表中获取当前Alpha_ID
的所有可用Num_ID
值,并从中删除所有值之前已被使用过。
可以在不使用显式变量INSERT
的情况下编写@CurrAlphaID
,但它对变量看起来更清晰。
这是SQL Fiddle。
DECLARE @TSrc TABLE (Num_ID varchar(10), Alpha_ID varchar(10));
INSERT INTO @TSrc (Num_ID, Alpha_ID) VALUES
('1', 'A'),
('1', 'B'),
('1', 'C'),
('2', 'B'),
('2', 'C'),
('3', 'A'),
('3', 'C'),
('4', 'A'),
('4', 'C'),
('5', 'A'),
('5', 'B'),
('5', 'C'),
('6', 'D'),
('6', 'E');
DECLARE @TDst TABLE (Num_ID varchar(10), Alpha_ID varchar(10));
DECLARE @CurrNumID varchar(10);
DECLARE @CurrAlphaID varchar(10);
DECLARE @iFS int;
DECLARE @VarCursor CURSOR;
SET @VarCursor = CURSOR FAST_FORWARD
FOR
SELECT DISTINCT Num_ID
FROM @TSrc
ORDER BY Num_ID;
OPEN @VarCursor;
FETCH NEXT FROM @VarCursor INTO @CurrNumID;
SET @iFS = @@FETCH_STATUS;
WHILE @iFS = 0
BEGIN
SET @CurrAlphaID =
(
SELECT TOP(1) Diff.Alpha_ID
FROM
(
SELECT Src.Alpha_ID
FROM @TSrc AS Src
WHERE Src.Num_ID = @CurrNumID
EXCEPT
SELECT Dst.Alpha_ID
FROM @TDst AS Dst
) AS Diff
ORDER BY Diff.Alpha_ID
);
INSERT INTO @TDst (Num_ID, Alpha_ID)
VALUES (@CurrNumID, @CurrAlphaID);
FETCH NEXT FROM @VarCursor INTO @CurrNumID;
SET @iFS = @@FETCH_STATUS;
END;
CLOSE @VarCursor;
DEALLOCATE @VarCursor;
SELECT * FROM @TDst;
<强>结果强>
Num_ID Alpha_ID
1 A
2 B
3 C
4 NULL
5 NULL
6 D
在源表上拥有(Num_ID, Alpha_ID)
索引会有所帮助。在目的地表上拥有(Alpha_ID)
索引也会有所帮助。
答案 1 :(得分:0)
我认为我已经通过递归(光标或一段时间)制作了一些东西
首先,我创建了一个包含行的表。
create table #tmptest
(
Num_ID int
, Alpha_ID varchar(50)
)
insert into #tmptest (Num_ID, Alpha_ID) values
(1,'A'),
(1,'B'),
(1,'C'),
(2,'B'),
(2,'C'),
(3,'A'),
(4,'C'),
(5,'A'),
(5,'B')
// this one, with row column
SELECT
ROW_NUMBER() OVER (PARTITION BY Num_ID ORDER BY Num_ID ASC) as row
, *
INTO #tmp_withrow
FROM #tmptest
这些是结果
最后,我做了一个内部查询(可能是左连接或更好)。
SELECT DISTINCT
Num_ID
, (
SELECT
TOP 1
Alpha_ID
FROM #tmp_withrow in1
WHERE
in1.Num_ID = t.Num_ID
AND in1.Alpha_ID NOT IN (
SELECT
Alpha_ID
FROM #tmp_withrow in2
WHERE
in2.Num_ID < in1.Num_ID
AND in2.row = 1
)
ORDER BY in1.Num_ID ASC
) AS [NonRepeatingAlpha]
from #tmptest t
这些是结果
注意:我创建了一个标记(row
),可以让您查询所有少于您(in2.Num_ID < in1.Num_ID
)的ID,然后找出哪些字母在哪里已使用(in2.row = 1
),然后选择/避免已从其他Num_ID使用的所有字母(
WHERE in1.Num_ID = t.Num_ID
AND in1.Alpha_ID NOT IN (
SELECT
Alpha_ID
FROM #tmp_withrow in2
WHERE
in2.Num_ID < in1.Num_ID
AND in2.row = 1
)
我希望这会有所帮助。谢谢!