استعلام بسيط للاستيلاء على القيمة القصوى لكل معرف

StackOverflow https://stackoverflow.com/questions/755918

سؤال

حسنا، لدي طاولة مثل هذا:

ID     Signal    Station    OwnerID
111     -120      Home       1
111     -130      Car        1
111     -135      Work       2
222     -98       Home       2
222     -95       Work       1
222     -103      Work       2

هذا هو كل شيء في نفس اليوم. أنا فقط بحاجة إلى الاستعلام لإرجاع إشارة أقصى لكل معرف:

ID    Signal    Station    OwnerID
111   -120      Home        1
222   -95       Work        1

حاولت استخدام MAX () ويفترض التجميع مع المحطة والمكافترين يختلف عن كل سجل. هل أحتاج إلى القيام بالانضمام؟

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

المحلول

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

select cur.id, cur.signal, cur.station, cur.ownerid
from yourtable cur
where not exists (
    select * 
    from yourtable high 
    where high.id = cur.id 
    and high.signal > cur.signal
)

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

نصائح أخرى

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

هناك عدد من الأساليب (كل من ANSI القياسية الخاصة بائع البائعين) لهذه المشكلة، معظمها هي الأمثل ذات المستوى الأمثل في العديد من الحالات. سيمنحك البعض صفوفا متعددة عندما يشارك أكثر من صف واحد نفس القيمة / الحد الأدنى للحد الأدنى؛ البعض لن. بعض العمل بشكل جيد على الجداول مع عدد صغير من المجموعات؛ البعض الآخر أكثر كفاءة لعدد أكبر من المجموعات ذات صفوف أصغر لكل مجموعة.

هنا مناقشة من بعض من تلك المشتركة (متحيزة MySQL ولكنها قابلة للتطبيق بشكل عام). شخصيا، إذا كنت أعرف أنه لا توجد أقسى متعددة (أو لا تهتم بالحصول عليها)، فغالبا ما تميل إلى طريقة الانضمام ذات الأيسر غير اليساري، والتي سأقوم بنشرها كما لم يكن أحد آخر:

SELECT reading.ID, reading.Signal, reading.Station, reading.OwnerID
FROM readings AS reading
LEFT JOIN readings AS highersignal
    ON highersignal.ID=reading.ID AND highersignal.Signal>reading.Signal
WHERE highersignal.ID IS NULL;

في SQL-92 الكلاسيكية (عدم استخدام عمليات OLAP المستخدمة بواسطة Quassnoi)، يمكنك استخدام:

SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID
  FROM (SELECT id, MAX(Signal) AS MaxSignal
          FROM t
          GROUP BY id) AS g
       JOIN t ON g.id = t.id AND g.MaxSignal = t.Signal;

(بناء جملة غير محدد؛ يفترض الجدول الخاص بك هو "T".)

يحدد الاستعلام الفرعي في الفقرة من أعلى قيمة الإشارة القصوى لكل معرف؛ يجمع الانضمام مع وجود صف البيانات المقابلة من الجدول الرئيسي.

ملحوظة: إذا كانت هناك العديد من الإدخالات لمعرفة معرف معين تحتوي جميعها على نفس قوة الإشارة وأن هذه القوة هي الحد الأقصى ()، فستحصل على العديد من صفوف الإخراج لهذا المعرف.


تم اختباره مقابل IBM Informix Dynamic Server 11.50.fc3 يعمل على Solaris 10:

+ CREATE TEMP TABLE signal_info
(
    id      INTEGER NOT NULL,
    signal  INTEGER NOT NULL,
    station CHAR(5) NOT NULL,
    ownerid INTEGER NOT NULL
);
+ INSERT INTO signal_info VALUES(111, -120, 'Home', 1);
+ INSERT INTO signal_info VALUES(111, -130, 'Car' , 1);
+ INSERT INTO signal_info VALUES(111, -135, 'Work', 2);
+ INSERT INTO signal_info VALUES(222, -98 , 'Home', 2);
+ INSERT INTO signal_info VALUES(222, -95 , 'Work', 1);
+ INSERT INTO signal_info VALUES(222, -103, 'Work', 2);
+ SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID
  FROM (SELECT id, MAX(Signal) AS MaxSignal
            FROM signal_info
            GROUP BY id) AS g
      JOIN signal_info AS t  ON g.id = t.id AND g.MaxSignal = t.Signal;

111     -120    Home    1
222     -95     Work    1

قمت بتسمية Signal Signal_info لهذا الاختبار - ولكن يبدو أنه ينتج الإجابة الصحيحة. هذا يدل فقط أن هناك DBMS واحد على الأقل يدعم التدوين. ومع ذلك، أنا مندهش قليلا أن MS SQL Server لا - ما هو الإصدار الذي تستخدمه؟


لا تتوقف أبدا عن مفاجأة لي كم مرة يتم تقديم أسئلة SQL دون أسماء جدول.


with tab(id, sig, sta, oid) as
(
select 111 as id, -120 as signal, 'Home' as station, 1 as ownerId union all
select 111, -130, 'Car',  1 union all
select 111, -135, 'Work', 2 union all
select 222, -98, 'Home',  2 union all
select 222, -95, 'Work',  1 union all
select 222, -103, 'Work', 2
) ,
tabG(id, maxS) as
(
   select id, max(sig) as sig from tab group by id
)
select g.*, p.* from tabG g
cross apply ( select  top(1) * from tab t where t.id=g.id order by t.sig desc ) p

WITH q AS
         (
         SELECT  c.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY signal DESC) rn
         FROM    mytable
         )
SELECT   *
FROM     q
WHERE    rn = 1

سيعود هذا صف واحد حتى لو كان هناك تكرارات MAX(signal) لاجل منحه ID.

وجود مؤشر على (id, signal) سوف يحسن هذا الاستعلام إلى حد كبير.

يمكننا أن نفعل استخدام الانضمام الذاتي

SELECT  T1.ID,T1.Signal,T2.Station,T2.OwnerID
FROM (select ID,max(Signal) as Signal from mytable group by ID) T1
LEFT JOIN mytable T2
ON T1.ID=T2.ID and T1.Signal=T2.Signal;

أو يمكنك أيضا استخدام الاستعلام التالي

SELECT t0.ID,t0.Signal,t0.Station,t0.OwnerID 
FROM mytable t0 
LEFT JOIN mytable t1 ON t0.ID=t1.ID AND t1.Signal>t0.Signal 
WHERE t1.ID IS NULL;
select a.id, b.signal, a.station, a.owner from 
mytable a
join 
(SELECT ID, MAX(Signal) as Signal FROM mytable GROUP BY ID) b
on a.id = b.id AND a.Signal = b.Signal 
حدد * من Stationable حيث الإشارة في (حدد A.MaxSignal من (حدد معرف، كحد أقصى (إشارة) ك MaxSignal من مجموعة StationBable by ID) ك A)؛

اختر المعرف، MAX_Signal، المالك، OpertionID من (حدد *، رتبة () Over (Partition by ID Order بواسطة Signal Desc) ك Max_Signal من الجدول) حيث Max_Signal = 1؛

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top