简体   繁体   中英

Get count of children from each parent.SQL Server 2012

I have 2 databases that are supposed to be identical. For some tables I need to compare and count how many children a parent got and compare this with the identical database.

Is what I have done below the correct way to get count of children? Is there a better way?

Put together below a sample with some dummy data."Employee" table with addresses Comparing how many addresses each employee has.

The desired result is what I already get, but I'm wondering again if there is a better way to do this.

Desired result:

EmployeeId  TotalAddressesA TotalAddressesB
1           4               1
2           2               5

Setup:

    IF OBJECT_ID('tempdb..#EmployeeDBA') IS NOT NULL DROP TABLE #EmployeeDBA
    IF OBJECT_ID('tempdb..#EmployeeDBAddressA') IS NOT NULL DROP TABLE #EmployeeDBAddressA
    IF OBJECT_ID('tempdb..#EmployeeDBB') IS NOT NULL DROP TABLE #EmployeeDBB
    IF OBJECT_ID('tempdb..#EmployeeDBAddressB') IS NOT NULL DROP TABLE #EmployeeDBAddressB

    CREATE TABLE #EmployeeDBA
    (   [EmployeeId] [int] NOT NULL,
        [Name] [varchar](50) NULL,
        [Surname] [varchar](50) NULL
    )

    CREATE TABLE #EmployeeDBB
    (   [EmployeeId] [int] NOT NULL,
        [Name] [varchar](50) NULL,
        [Surname] [varchar](50) NULL
    )
    CREATE TABLE #EmployeeDBAddressA
    (   [EmployeeAddressId] [int] NOT NULL,
         [EmployeeId][int] NOT NULL,
        [Addresss] [varchar](50) NULL,
    )
    CREATE TABLE #EmployeeDBAddressB
    (   [EmployeeAddressId] [int] NOT NULL,
         [EmployeeId][int] NOT NULL,
        [Addresss] [varchar](50) NULL,
    )

    INSERT #EmployeeDBA (EmployeeId,Name,Surname)
    VALUES(1,'Jo','Bloggs'),(2,'Mark','Smith')

    INSERT #EmployeeDBB (EmployeeId,Name,Surname)
    VALUES(1,'Jo','Bloggs'),(2,'Mark','Smith')

    INSERT #EmployeeDBAddressA(EmployeeAddressId,EmployeeId,Addresss)
    VALUES(1,1,'Address1ForEmployee1'),
    (2,1,'Address2ForEmployee1'),
    (3,1,'Address3ForEmployee1'), 
    (4,1,'Address4ForEmployee1'),
    (5,2,'Address1ForEmployee2'),
    (6,2,'Address2ForEmployee2')      


    INSERT #EmployeeDBAddressB(EmployeeAddressId,EmployeeId,Addresss)
    VALUES(1,1,'Address1ForEmployee1'),
    (2,2,'Address1ForEmployee2'),
    (3,2,'Address2ForEmployee2'),
    (4,2,'Address3ForEmployee2'),
    (5,2,'Address4ForEmployee2'),
    (6,2,'Address5ForEmployee2')


    --BELOW IS WHAT I AM QUERYING IF IT'S BEST WAY TO FIND COUNT OF CHILDREN FOR EACH PARENT.
    ;WITH CTEA
         AS ( SELECT A.EmployeeId,
                     TotalCountA = ( 
                                          SELECT COUNT(EmployeeId)
                                          FROM #EmployeeDBAddressA b
                                          WHERE b.EmployeeId = a.EmployeeId)
              FROM #EmployeeDBA A
              GROUP BY A.EmployeeId ),
         CTEB
         AS (SELECT A.EmployeeId,
                     TotalCountB = ( 
                                          SELECT COUNT(EmployeeId)
                                          FROM #EmployeeDBAddressB b
                                          WHERE b.EmployeeId = a.EmployeeId)
              FROM #EmployeeDBB A
              GROUP BY A.EmployeeId )

        --is this the way to compare totals betwen 2 tables   

        SELECT A.EmployeeId,A.TotalCountA,B.TotalCountB
        FROM CTEA A
                LEFT JOIN CTEB B ON A.EmployeeId = B.EmployeeId
        WHERE ISNULL(A.TotalCountA, 0) <> ISNULL(B.TotalCountB, 0);


    DROP TABLE #EmployeeDBA
    DROP TABLE #EmployeeDBAddressA
    DROP TABLE #EmployeeDBB
    DROP TABLE #EmployeeDBAddressB

I'd use FULL JOIN when joining CTEs instead of LEFT JOIN to catch missing Employees in both tables. In your current variant with LEFT JOIN , if EmployeeDBA has no rows, but EmployeeDBB has rows, your query would return empty result set, even though the tables are different.

In the CTE I'd join two tables instead of calculating COUNT in subquery. Though, it is likely that optimizer would generate the same plan.

WITH 
CTEA
AS
(
    SELECT
        Emp.EmployeeId
        ,COUNT(Addr.EmployeeId) AS TotalCountA
    FROM
        #EmployeeDBA AS Emp
        LEFT JOIN #EmployeeDBAddressA AS Addr ON Addr.EmployeeId = Emp.EmployeeId
        -- LEFT JOIN for those Employees that don't have addresses
    GROUP BY Emp.EmployeeId
)
,CTEB
AS
(
    SELECT
        Emp.EmployeeId
        ,COUNT(Addr.EmployeeId) AS TotalCountA
    FROM
        #EmployeeDBB AS Emp
        LEFT JOIN #EmployeeDBAddressB AS Addr ON Addr.EmployeeId = Emp.EmployeeId
        -- LEFT JOIN for those Employees that don't have addresses
    GROUP BY Emp.EmployeeId
)
SELECT
    COALESCE(CTEA.EmployeeId, CTEB.EmployeeId) AS EmployeeId
    ,CTEA.TotalCountA
    ,CTEB.TotalCountB
FROM
    CTEA
    FULL JOIN CTEB ON CTEA.EmployeeId = CTEB.EmployeeId
    -- FULL JOIN to catch missing Employees in both tables
WHERE
    ISNULL(CTEA.TotalCountA, 0) <> ISNULL(CTEB.TotalCountB, 0)
;

You can try this code:

   SELECT * FROM (
        SELECT EmployeeId
        FROM #EmployeeDBA
        UNION
        SELECT EmployeeId
        FROM #EmployeeDBB) AS C
    CROSS APPLY (
        SELECT COUNT(*) AS TotalCountA
        FROM #EmployeeDBAddressA WHERE EmployeeId = C.EmployeeId
    ) AS A
    CROSS APPLY (
        SELECT COUNT(*) AS TotalCountB
        FROM #EmployeeDBAddressB WHERE EmployeeId = C.EmployeeId
    ) AS B

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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