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.