سؤال

لدي جدول يحتوي على عمودين، دعنا نقول الاسم الأول واسم العائلة.أحتاج إلى الحصول على جدول آخر، والذي يحتوي لكل زوج من الأسماء الأولى من الأول على عدد من أسماء العائلة الشائعة.

هل هذا ممكن القيام به في SQL؟

يوجد اسم عائلة فريد أكثر بكثير من الاسم الأول، إذا كان هذا يؤثر على كفاءة الاستعلام.

مثال على لعبة، الإدخال:

FirstName, LastName
John, Smith
John, Doe
Jane, Doe

انتاج:

FirstName1, FirstName2, CommonLastNames
John, John, 2
John, Jane, 1
Jane, Jane, 1
Jane, John, 1

بما أن هذه العلاقة انعكاسية ومتماثلة، فلا بأس إذا كانت النتيجة مجرد أحد المثلثات (على سبيل المثال، المثلث الموجود فوق القطر).

هل كانت مفيدة؟

المحلول

سأستخدم MS SQL Server للقيام بذلك نظرًا لأن لدي نسخة في متناول اليد.أعتقد أن معظم الشركات الكبرى ستفعل ذلك بالمثل.

أولاً جدول عينة، مع البيانات.أستخدم متغير جدول ولكنه هو نفسه بالنسبة لأي نكهة طاولة.

declare @t table (FirstName char(10), LastName char(10));

insert @t(FirstName,LastName)
values ('John','Smith'),('John','Doe'),('Jane','Doe');

يمكنك الحصول على جميع الأزواج عن طريق الانضمام الذاتي:

select
    a.FirstName, a.LastName, b.FirstName, b.LastName
from @t as a
cross apply @t as b;

استخدام CROSS APPLY يتجنب الاضطرار إلى القفز عبر الأطواق للعثور على شرط الانضمام لـ ON بند.

القادمة تحتاج إلى شيء لحساب.هذا هو المكان CASE يأتي البيان.تُرجع الحالة قيمة عددية صحيحة لكل زوج من الأسماء الأولى، وهو ما يتم حسابه.(إذا كنت أقرأ سؤالك بشكل صحيح، فأنت تريد تطابق أسماء العائلة، وهذه هي المقارنة التي أجريتها.نأمل أن يكون من الواضح كيفية تعديل هذا إذا كنت مخطئًا.)

select
    ...
    case
        when a.LastName = b.LastName then 1
        else 0
    end
...etc.

أضف في أ SUM() و GROUP BY وتحصل على إجابتك:

select
    a.FirstName,
    b.FirstName,
    sum(
    case
        when a.LastName = b.LastName then 1
        else 0
    end
    ) as CommonLastNames
from @t as a
cross apply @t as b
group by a.FirstName, b.FirstName;

نصائح أخرى

يجب أن أعترف أن سؤالي كان معيبا بعض الشيء. ما كنت بحاجة إليه حقا لم يكن "لكل زوج من الاسم الأول من أول واحد يحتوي على عدد من العائلة المشتركة".في الواقع، أنا لا أهتم بأزواج مع عدد الصفر.

عندما يتم تصحيح السؤال، يصبح الحل أسرع بكثير.

إعطاء المدخلات:

giveacodicetagpre.

للحصول على السؤال الأصلي، الحل هو O (n ^ 2) (لأن السؤال يصر على "كل زوج"):

giveacodicetagpre.

إذا كان من الجيد تخطي عدد الصفر، فإن الانضمام الذاتي على اسم العائلة يعمل بشكل أسرع بكثير (بافتراض أن البيانات متناثرة بما فيه الكفاية):

giveacodicetagpre.

ما زلت أتساءل كيف فاتني هذا الحل الفاتح.

doh!إليك طريقة أفضل:

giveacodicetagpre.

الإخراج:

giveacodicetagpre.

secity تحقق في البند الأول:

giveacodicetagpre.

توضح قيم الحالة الرئيسية٪ أنها فعلت الكثير من العمل، ولكن ليس تماما (n * n) (ربما لأن الانضمام الصليب هو حالة واحدة فقط في كل مرة):

giveacodicetagpre.

الاستقراء إلى ملايين الصفوف - من المحتمل أن يستغرق الأمر أياما.

لقد كان ذلك تحديًا مثيرًا للاهتمام.باستخدام قائمة المدن الأمريكية، توصلت إلى هذا الحل (في MySQL):

SELECT  city_a, city_b,
        COUNT(DISTINCT state)
    FROM (
        ( SELECT a.city city_a,
                 b.city city_b,
                 a.state            -- This line differs
            FROM       us a
            CROSS JOIN us b
            WHERE a.state = b.state
              AND a.city != b.city   -- Added (to avoid noise)
              AND a.city < 'M'    -- to speed up test
              AND b.city < 'M'
        )
        UNION ALL
        ( SELECT a.city city_a,
                 b.city city_b,
                 b.state            -- This line differs
            FROM       us a
            CROSS JOIN us b
            WHERE a.state = b.state
              AND a.city != b.city   -- Added (to avoid noise)
              AND a.city < 'M'    -- to speed up test
              AND b.city < 'M'
        )
        ) ab
    GROUP BY 1, 2
    HAVING   COUNT(DISTINCT state) > 1
    ORDER BY COUNT(DISTINCT state) desc

INDEX(state, city) يساعد في الأداء.

النتائج:

+----------+------------+-----------------------+
| city_a   | city_b     | COUNT(DISTINCT state) |
+----------+------------+-----------------------+
| Franklin | Bedford    |                     4 |
| Lebanon  | Franklin   |                     4 |
| Franklin | Lebanon    |                     4 |
| Hudson   | Franklin   |                     4 |
| Columbia | Clinton    |                     4 |
| Clinton  | Columbia   |                     4 |
| Franklin | Hudson     |                     4 |
| Bedford  | Franklin   |                     4 |
| Lebanon  | Farmington |                     3 |
| Hanover  | Kingston   |                     3 |
...
(25.17 sec)

ربما استغرق الأمر 4 أضعاف الوقت لتضمين الأبجدية بأكملها.لم يكن هناك سوى 4K من الصفوف في الجدول، لذلك هذا هو لا مهمة سريعة.

"إثبات" النتائج:Mysql> حدد المدينة، الولاية التي تقع فيها المدينة ('Franklin'، 'Bedford')؛

+----------+-------+
| city     | state |
+----------+-------+
| Bedford  | IN    |
| Franklin | IN    |
| Bedford  | MA    |
| Franklin | MA    |
| Bedford  | NH    |
| Franklin | NH    |
| Bedford  | OH    |
| Franklin | OH    |
| Franklin | TN    |
| Bedford  | TX    |
| Franklin | WI    |
+----------+-------+
11 rows in set (0.00 sec)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى dba.stackexchange
scroll top