查询将表中的值相互比较基于特定列中的值并仅显示区分忽略空值

时间:2015-05-26 14:34:28

标签: sql sql-server

我已经尽力让这一点尽可能清晰,但我确实感激不尽,有点令人困惑。我甚至在标题上遇到了一些麻烦。我为此道歉。如果有任何问题需要澄清,请随时提出任何问题,如果有任何帮助,我将对其进行编辑。

我已经搜索了很长一段时间,但我找不到任何东西。有一段时间我以为我需要使用Pivot,这对我来说是全新的,但现在我没想到。任何帮助将不胜感激,提前谢谢。

我有一张表格,其中显示了在不同位置使用的不同代码和说明。我需要将这些位置合二为一。在我能够做到这一点之前,我需要能够清楚地看到两组数据,给定位置的给定类别中的代码使用的不同描述,以及给定类别中给定类别的描述的不同代码位置,所以我可以得到数据同意。虽然给定代码每个位置每个类别只有一个描述,但给定描述每个位置每个类别可以有多个代码。我只关注在不同地点使用不同代码和类别的情况。出于这些目的,在一个或多个位置相同但未在其他位置使用的代码或描述没有不同。

我需要能够运行一个查询,为给定的类别和代码显示我们按位置的所有描述,包括不使用该代码的空值,其中所有位置的描述都不相同。同样,如果代码没有除null之外的差异,则它不应该在列表中。

我需要能够运行另一个查询,为给定的类别和描述显示所有代码的位置,包括不使用该描述的空值,其中所有位置的代码都不相同请记住,每个位置可能有多个代码。同样如上所述,如果给定类别和描述的代码相同,但未在所有位置使用,则不应返回。

所以,如果我的表有:

LOCATION    CATEGORY    CODE    DESCR
aaa         Dept        001     Pharmacy
bbb         Dept        001     Pharmacy
ccc         Dept        002     Pharmacy
ddd         Dept        002     Labratory
aaa         Dept        003     Clerical
bbb         Dept        003     Laundry
ccc         Dept        003     IT
ddd         Dept        003     Accounting
aaa         Dept        004     Purchasing
bbb         Dept        004     Purchasing
ccc         Dept        004     Purchasing
ddd         Dept        004     Purchasing
aaa         Job         004     Recepionist
bbb         Job         004     Recepionist
bbb         Job         104     Recepionist
ccc         Job         004     Recepionist
ddd         Job         004     Recepionist

相同代码不同的描述

CATEGORY    CODE    aaa_DESCR   bbb_DESCR   ccc_DESCR   ddd_DESCR
Dept        002     NULL        NULL        Pharmacy    Labratory
Dept        003     Clerical    Laundry     IT          Accounting

相同描述不同代码

CATEGORY    DESCR       aaa_CODE1   bbb_CODE1   bbb_CODE2   ccc_CODE1   ddd_CODE1
Dept        Pharmacy    001         001         NULL        002         NULL
Job         Recepionist 004         004         104         004         004

如果有多个列在给定位置有相同描述的多个代码是不可能的,那么也许可以将该位置的所有代码放在由特定字符分隔的一列中,像这样:

CATEGORY    DESCR       aaa_CODE    bbb_CODE    ccc_CODE    ddd_CODE
Dept        Pharmacy    001         001         002         NULL
Job         Recepionist 004         004|104     004         004

1 个答案:

答案 0 :(得分:2)

您需要的第一步是确定需要格式化的行,因此,对于您要查找相同代码和类别具有多个描述的位置的第一个标准,我会使用EXISTS:< / p>

SELECT  t.Location, t.Category, t.Code, t.Descr
FROM    #T AS t
WHERE   EXISTS
        (   SELECT  1
            FROM    #T AS t2
            WHERE   t2.Category = t.Category
            AND     t2.Code = t.Code
            AND     t2.Descr != t.Descr
        );

这给出了我们需要格式化的行:

Location    Category    Code    Descr
-------------------------------------------
ccc         Dept        002     Pharmacy
ddd         Dept        002     Labratory
aaa         Dept        003     Clerical
bbb         Dept        003     Laundry
ccc         Dept        003     IT
ddd         Dept        003     Accounting

然后,如果您对每个类别,代码和位置都有唯一的Desc,就像我们在这里一样,您可以在PIVOT函数中使用任意聚合来获得所需的格式:

SELECT  pvt.Category,
        pvt.[aaa], 
        pvt.[bbb], 
        pvt.[ccc], 
        pvt.[ddd]
FROM    (   SELECT  t.Location, t.Category, t.Code, t.Descr
            FROM    #T AS t
            WHERE   EXISTS
                    (   SELECT  1
                        FROM    #T AS t2
                        WHERE   t2.Category = t.Category
                        AND     t2.Code = t.Code
                        AND     t2.Descr != t.Descr
                    )
        ) AS t
        PIVOT
        (   MAX(Descr)
            FOR Location IN ([aaa], [bbb], [ccc], [ddd])
        ) AS pvt;

如果您有多个值,则会变得更加复杂,因此您无法在MAX内使用PIVOT。在这里,您需要使用SQL Server's XML extensions to concatenate your similar rows into a single row

以下使用相同的EXISTS逻辑来查找正确的行,但不是仅仅选择Code使用子库来收集(Category, Location, Descr)特定组合的所有代码并将它们组合成一个记录:

SELECT  t.Location, 
        t.Category, 
        t.Descr,
        Code = STUFF((  SELECT '|' + t2.Code
                        FROM    #T AS t2
                        WHERE   t2.Category = t.Category
                        AND     t2.Descr = t.Descr
                        AND     t2.Location = t.Location
                        FOR XML PATH(''), TYPE
                        ).value('.', 'VARCHAR(MAX)'), 1, 1, '')
FROM    #T AS t
WHERE   EXISTS
        (   SELECT  1
            FROM    #T AS t2
            WHERE   t2.Category = t.Category
            AND     t2.Descr = t.Descr
            AND     t2.Code != t.Code
        )
GROUP BY t.Location, t.Category, t.Descr;

这给出了:

Location    Category    Descr       Code
--------------------------------------------
aaa         Dept        Pharmacy    001
aaa         Job         Recepionist 004
bbb         Dept        Pharmacy    001
bbb         Job         Recepionist 004|104
ccc         Dept        Pharmacy    002
ccc         Job         Recepionist 004
ddd         Job         Recepionist 004

获得此格式后,您可以再次使用PIVOT获取所需的输出。

SELECT  pvt.Category,
        pvt.[aaa], 
        pvt.[bbb], 
        pvt.[ccc], 
        pvt.[ddd]
FROM    (   SELECT  t.Location, 
                    t.Category, 
                    t.Descr,
                    Code = STUFF((  SELECT '|' + t2.Code
                                    FROM    #T AS t2
                                    WHERE   t2.Category = t.Category
                                    AND     t2.Descr = t.Descr
                                    AND     t2.Location = t.Location
                                    FOR XML PATH(''), TYPE
                                    ).value('.', 'VARCHAR(MAX)'), 1, 1, '')
            FROM    #T AS t
            WHERE   EXISTS
                    (   SELECT  1
                        FROM    #T AS t2
                        WHERE   t2.Category = t.Category
                        AND     t2.Descr = t.Descr
                        AND     t2.Code != t.Code
                    )
            GROUP BY t.Location, t.Category, t.Descr
        ) AS t
        PIVOT
        (   MAX(Code)
            FOR Location IN ([aaa], [bbb], [ccc], [ddd])
        ) AS pvt;

<强> Examples of Both Queries on SQL Fiddle

为了完整性,下面是我用于测试的表格:

CREATE TABLE #T (Location VARCHAR(3), Category VARCHAR(4), Code CHAR(3), Descr VARCHAR(50));

INSERT INTO #T (Location, Category, Code, Descr)
VALUES
    ('aaa', 'Dept', '001', 'Pharmacy'),
    ('bbb', 'Dept', '001', 'Pharmacy'),
    ('ccc', 'Dept', '002', 'Pharmacy'),
    ('ddd', 'Dept', '002', 'Labratory'),
    ('aaa', 'Dept', '003', 'Clerical'),
    ('bbb', 'Dept', '003', 'Laundry'),
    ('ccc', 'Dept', '003', 'IT'),
    ('ddd', 'Dept', '003', 'Accounting'),
    ('aaa', 'Dept', '004', 'Purchasing'),
    ('bbb', 'Dept', '004', 'Purchasing'),
    ('ccc', 'Dept', '004', 'Purchasing'),
    ('ddd', 'Dept', '004', 'Purchasing'),
    ('aaa', 'Job', '004', 'Recepionist'),
    ('bbb', 'Job', '004', 'Recepionist'),
    ('bbb', 'Job', '104', 'Recepionist'),
    ('ccc', 'Job', '004', 'Recepionist'),
    ('ddd', 'Job', '004', 'Recepionist');