it-swarm.asia

استعلام SQL لإرجاع الاختلافات بين جدولين

أحاول مقارنة جدولين ، SQL Server ، للتحقق من بعض البيانات. أريد إرجاع جميع الصفوف من كلا الجدولين حيث توجد البيانات في أحدهما أو آخر. في جوهرها ، أريد أن أظهر كل التناقضات. أحتاج إلى التحقق من ثلاثة أجزاء من البيانات في القيام بذلك ، الاسم الأول واسم العائلة والمنتج.

أنا جديد إلى حد ما على SQL ويبدو أن الكثير من الحلول التي أجدها تزيد من تعقيد الأمور. لا داعي للقلق حول القيم الخالية.

لقد بدأت بمحاولة شيء مثل هذا:

SELECT DISTINCT [First Name], [Last Name], [Product Name] FROM [Temp Test Data]
WHERE ([First Name] NOT IN (SELECT [First Name] 
FROM [Real Data]))

أواجه مشكلة مع هذا أبعد من ذلك.

شكر!

تصحيح:

بناءً على إجابةtreaschf ، كنت أحاول استخدام صيغة مختلفة من الاستعلام التالي:

SELECT td.[First Name], td.[Last Name], td.[Product Name]
FROM [Temp Test Data] td FULL OUTER JOIN [Data] AS d 
ON td.[First Name] = d.[First Name] AND td.[Last Name] = d.[Last Name] 
WHERE (d.[First Name] = NULL) AND (d.[Last Name] = NULL)

لكنني ما زلت أحصل على 0 نتائج ، عندما أعرف أن هناك صفًا واحدًا على الأقل في td غير موجود في d.

تصحيح:

حسنا ، أعتقد أنني أحسب ذلك. على الأقل في دقائقي القليلة من الاختبار ، يبدو أنه يعمل بشكل جيد بما فيه الكفاية.

SELECT [First Name], [Last Name]
FROM [Temp Test Data] AS td
WHERE (NOT EXISTS
        (SELECT [First Name], [Last Name]
         FROM [Data] AS d
         WHERE ([First Name] = td.[First Name]) OR ([Last Name] = td.[Last Name])))

سيقوم هذا في الأساس بإخباري بما يوجد في بيانات الاختبار الخاصة بي لا في بياناتي الحقيقية. وهو أمر جيد تمامًا لما أحتاج إلى فعله.

160
Casey

إذا كان لديك جدولان A و B ، وكلاهما مع colum C ، فهذه هي السجلات الموجودة في الجدول A لكن ليس في B:

SELECT A.*
FROM A
    LEFT JOIN B ON (A.C = B.C)
WHERE B.C IS NULL

للحصول على جميع الاختلافات مع استعلام واحد ، يجب استخدام صلة كاملة ، مثل هذا:

SELECT A.*, B.*
FROM A
    FULL JOIN B ON (A.C = B.C)
WHERE A.C IS NULL OR B.C IS NULL

ما تحتاج إلى معرفته في هذه الحالة هو أنه عندما يمكن العثور على سجل في A ، وليس في B ، ستكون الأعمدة التي تأتي من B فارغة ، وبالمثل لتلك الموجودة في B وليس في A ، ستكون الأعمدة من A خالية.

177
treaschf
(   SELECT * FROM table1
    EXCEPT
    SELECT * FROM table2)  
UNION ALL
(   SELECT * FROM table2
    EXCEPT
    SELECT * FROM table1) 
217
erikkallen

أعلم أن هذا قد لا يكون إجابة شائعة ولكنني أتفق معRandy Minder على استخدام أداة الطرف الثالث عند الحاجة إلى مقارنة أكثر تعقيدًا.

هذه الحالة المحددة هنا سهلة ، وفي هذه الحالة ليست هناك حاجة إلى مثل هذه الأدوات ، لكن يمكن أن تصبح معقدة بسهولة إذا قمت بتقديم المزيد من الأعمدة وقواعد البيانات على خادمين ومعايير مقارنة أكثر تعقيدًا.

هناك الكثير من هذه الأدوات مثل ApexSQL Data Diff أو Quest Toad ويمكنك دائمًا استخدامها في وضع الإصدار التجريبي لإنجاز المهمة.

36
Maisie John

للحصول على جميع الاختلافات بين جدولين ، يمكنك استخدام طلب SQL هذا مثلي:

SELECT 'TABLE1-ONLY' AS SRC, T1.*
FROM (
      SELECT * FROM Table1
      EXCEPT
      SELECT * FROM Table2
      ) AS T1
UNION ALL
SELECT 'TABLE2-ONLY' AS SRC, T2.*
FROM (
      SELECT * FROM Table2
      EXCEPT
      SELECT * FROM Table1
      ) AS T2
;
9
bilelovitch

إذا كنت ترغب في الحصول على قيم الأعمدة المختلفة ، فيمكنك استخدام نموذج Entity-Attribute-Value:

declare @Data1 xml, @Data2 xml

select @Data1 = 
(
    select * 
    from (select * from Test1 except select * from Test2) as a
    for xml raw('Data')
)

select @Data2 = 
(
    select * 
    from (select * from Test2 except select * from Test1) as a
    for xml raw('Data')
)

;with CTE1 as (
    select
        T.C.value('../@ID', 'bigint') as ID,
        T.C.value('local-name(.)', 'nvarchar(128)') as Name,
        T.C.value('.', 'nvarchar(max)') as Value
    from @Data1.nodes('Data/@*') as T(C)    
), CTE2 as (
    select
        T.C.value('../@ID', 'bigint') as ID,
        T.C.value('local-name(.)', 'nvarchar(128)') as Name,
        T.C.value('.', 'nvarchar(max)') as Value
    from @Data2.nodes('Data/@*') as T(C)     
)
select
    isnull(C1.ID, C2.ID) as ID, isnull(C1.Name, C2.Name) as Name, C1.Value as Value1, C2.Value as Value2
from CTE1 as C1
    full outer join CTE2 as C2 on C2.ID = C1.ID and C2.Name = C1.Name
where
not
(
    C1.Value is null and C2.Value is null or
    C1.Value is not null and C2.Value is not null and C1.Value = C2.Value
)

مثال SQL FIDDLE

4
Roman Pekar

يوجد تباين بسيط في إجابةerikkallen يوضح الجدول الذي يوجد فيه الصف في:

(   SELECT 'table1' as source, * FROM table1
    EXCEPT
    SELECT * FROM table2)  
UNION ALL
(   SELECT 'table2' as source, * FROM table2
    EXCEPT
    SELECT * FROM table1) 

إذا حصلت على خطأ

يجب أن تحتوي جميع الاستعلامات مجتمعة باستخدام عامل تشغيل UNION أو INTERSECT أو EXCEPT على عدد مساوٍ من التعبيرات في قوائمها المستهدفة.

ثم قد يساعد على إضافة

(   SELECT 'table1' as source, * FROM table1
    EXCEPT
    SELECT 'table1' as source, * FROM table2)  
UNION ALL
(   SELECT 'table2' as source, * FROM table2
    EXCEPT
    SELECT 'table2' as source, * FROM table1) 
3
studgeek

هذا سيفعل الخدعة ، مشابهًا مع حل Tiago ، وإرجاع جدول "المصدر" أيضًا.

select [First name], [Last name], max(_tabloc) as _tabloc
from (
  select [First Name], [Last name], 't1' as _tabloc from table1
  union all
  select [First name], [Last name], 't2' as _tabloc from table2
) v
group by [Fist Name], [Last name]
having count(1)=1

ستحتوي النتيجة على اختلافات بين الجداول ، في العمود _tabloc سيكون لديك مرجع للجدول.

2
Adrian-Bogdan Ionescu

جرب هذا :

SELECT 
    [First Name], [Last Name]
FROM 
    [Temp Test Data] AS td EXCEPTION JOIN [Data] AS d ON 
         (d.[First Name] = td.[First Name] OR d.[Last Name] = td.[Last Name])

أبسط بكثير للقراءة.

2
Kango_V

بالنسبة لاختبار الدخان البسيط ، حيث تحاول التأكد من مطابقة جدولين مع عدم القلق بشأن أسماء الأعمدة:

--ensure tables have matching records
Select count (*) from tbl_A
Select count (*) from tbl_B

--create temp table of all records in both tables
Select * into #demo from tbl_A 
Union All
Select * from tbl_B

--Distinct #demo records = Total #demo records/2 = Total tbl_A records = total tbl_B records
Select distinct * from #demo 

يمكنك بسهولة كتابة إجراء مخزن لمقارنة مجموعة من الجداول.

1
thomas398

هناك مشكلة في الأداء تتعلق بالصلة اليسرى وكذلك الصلة الكاملة بالبيانات الكبيرة.

في رأيي هذا هو الحل الأفضل:

select [First Name], count(1) e from (select * from [Temp Test Data] union all select * from [Temp Test Data 2]) a group by [First Name] having e = 1
0
Tiago Moutinho