简体   繁体   English

使用另一个表中的唯一值创建一个表

[英]Create a table with unique values from another table

I am using MS SQL Server Management Studio. 我正在使用MS SQL Server Management Studio。 I have table - 我有桌子 -

+--------+----------+
| Num_ID | Alpha_ID |
+--------+----------+
|   1    |    A     |
|   1    |    B     |
|   1    |    C     |
|   2    |    B     |
|   2    |    C     |
|   3    |    A     |
|   4    |    C     |
|   5    |    A     |
|   5    |    B     |
+--------+----------+

I want to create another table with 2 columns from this table so that column_1 gives Unique values in Num_ID (ie 1,2,3,4 and so on) and column_2 gives Unique values in Alpha_ID (A, B, C and so on). 我想创建另一个包含此表中2列的表,以便column_1在Num_ID中给出唯一值(即1,2,3,4等),column_2在Alpha_ID中给出唯一值(A,B,C等) 。

But if an alphabet has already occurred, it should not occur again. 但是如果已经发生了字母表,则不应该再次出现。 So the output will be something like this - 所以输出将是这样的 -

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) 
----------------

Hope that makes sense. 希望有道理。 I would like to clarify that the IDs in the input table are not numerical as I have shown, but both Num_ID and Alpha_ID are complex strings. 我想澄清一下,输入表中的ID不是我所示的数字,但Num_ID和Alpha_ID都是复杂的字符串。 I have simplified them to 1,2,3,... and A, B, C .... for the purpose of this question 为了这个问题的目的,我把它们简化为1,2,3,......和A,B,C ....

I don't think this could be done without a cursor. 我不认为没有光标就可以做到这一点。 I added few more rows to your sample data to test how it works with other cases. 我在您的示例数据中添加了更多行,以测试它与其他案例的工作方式。

The logic is straight-forward. 逻辑是直截了当的。 At first get a list of all distinct values of Num_ID . 首先获取Num_ID的所有不同值的Num_ID Then loop through them and with each iteration add one row to the destination table. 然后遍历它们并在每次迭代时向目标表添加一行。 To determine the Alpha_ID value to add I'll use EXCEPT operator that takes all available Alpha_ID values for the current Num_ID from the source table and removes from them all values that have been used before. 要确定要添加的Alpha_ID值,我将使用EXCEPT运算符,该运算符从源表中获取当前Num_ID所有可用Alpha_ID值,并Num_ID删除之前使用过的所有值。

It is possible to write that INSERT without using explicit variable @CurrAlphaID , but it looks a bit cleaner with variable. 可以在不使用显式变量@CurrAlphaID情况下编写INSERT ,但它看起来有点变得干净。

Here is SQL Fiddle . 这是SQL小提琴

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;

Result 结果

Num_ID    Alpha_ID
1         A
2         B
3         C
4         NULL
5         NULL
6         D

Having index on (Num_ID, Alpha_ID) on the source table would help. 在源表上具有索引(Num_ID, Alpha_ID)会有所帮助。 Having index on (Alpha_ID) on the destination table would help as well. 在目标表上具有索引(Alpha_ID)也会有所帮助。

I think I've made something not through a recursion (cursor or a while) 我想我已经做了一些不是通过递归(光标或一段时间)

First, I created a table with rows. 首先,我创建了一个包含行的表。

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

and these were the results 这些都是结果

在此输入图像描述

Lastly, I made an inner query (could possibly be a left join or better). 最后,我做了一个内部查询(可能是左连接或更好)。

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

and these were the results 这些都是结果

在此输入图像描述

Note : I created a flag ( row ) which will allow you to query all less than the ID's you're in ( in2.Num_ID < in1.Num_ID ) then find out what letters where already used ( in2.row = 1 ) and then select / avoid all letters that has already been used from the other Num_ID ( 注意:我创建了一个标志( row ),它允许您查询所有小于您所在的ID( in2.Num_ID < in1.Num_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

)

I hope this helps. 我希望这有帮助。 Thanks! 谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM