mysql - with - w3school php




احصل على سجلات ذات قيمة قصوى لكل مجموعة من نتائج SQL المجمعة (12)

إذا كانت هناك حاجة إلى معرف (وجميع coulmns) من mytable

SELECT
    *
FROM
    mytable
WHERE
    id NOT IN (
        SELECT
            A.id
        FROM
            mytable AS A
        JOIN mytable AS B ON A. GROUP = B. GROUP
        AND A.age < B.age
    )

كيف تحصل على الصفوف التي تحتوي على القيمة القصوى لكل مجموعة مجمعة؟

لقد رأيت بعض الاختلافات المعقدة جدًا في هذا السؤال ، ولا توجد إجابة جيدة. لقد حاولت أن أبسط أبسط مثال ممكن:

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

Person | Group | Age
---
Bob  | 1     | 32  
Jill | 1     | 34  
Shawn| 1     | 42  
Jake | 2     | 29  
Paul | 2     | 36  
Laura| 2     | 39  

مجموعة النتائج المطلوبة:

Shawn | 1     | 42    
Laura | 2     | 39  

اسم الجدول يكون الناس

select O.*              -- > O for oldest table
from people O , people T
where O.grp = T.grp and 
O.Age = 
(select max(T.age) from people T where O.grp = T.grp
  group by T.grp)
group by O.grp; 

باستخدام CTEs - تعبيرات جدول شائعة:

WITH MyCTE(MaxPKID, SomeColumn1)
AS(
SELECT MAX(a.MyTablePKID) AS MaxPKID, a.SomeColumn1
FROM MyTable1 a
GROUP BY a.SomeColumn1
  )
SELECT b.MyTablePKID, b.SomeColumn1, b.SomeColumn2 MAX(b.NumEstado)
FROM MyTable1 b
INNER JOIN MyCTE c ON c.MaxPKID = b.MyTablePKID
GROUP BY b.MyTablePKID, b.SomeColumn1, b.SomeColumn2

--Note: MyTablePKID is the PrimaryKey of MyTable

باستخدام طريقة الترتيب.

SELECT @rn :=  CASE WHEN @prev_grp <> groupa THEN 1 ELSE @rn+1 END AS rn,  
   @prev_grp :=groupa,
   person,age,groupa  
FROM   users,(SELECT @rn := 0) r        
HAVING rn=1
ORDER  BY groupa,age DESC,person

حل axiac هو أفضل ما يعمل بالنسبة لي في النهاية. ومع ذلك كان لدي تعقيد إضافي: "قيمة قصوى" محسوبة ، مشتقة من عمودين.

دعونا نستخدم نفس المثال: أود أن أقدم شخص في كل مجموعة. إذا كان هناك أشخاص مسنين بنفس القدر ، خذ أطول شخص.

واضطررت إلى تنفيذ الانضمام الأيسر مرتين للحصول على هذا السلوك:

SELECT o1.* WHERE
    (SELECT o.*
    FROM `Persons` o
    LEFT JOIN `Persons` b
    ON o.Group = b.Group AND o.Age < b.Age
    WHERE b.Age is NULL) o1
LEFT JOIN
    (SELECT o.*
    FROM `Persons` o
    LEFT JOIN `Persons` b
    ON o.Group = b.Group AND o.Age < b.Age
    WHERE b.Age is NULL) o2
ON o1.Group = o2.Group AND o1.Height < o2.Height 
WHERE o2.Height is NULL;

أتمنى أن يساعدك هذا! أعتقد أن هناك طريقة أفضل للقيام بذلك على الرغم من ...


حل بسيط ل SQLite (وربما MySQL):

SELECT *, MAX(age) FROM mytable GROUP BY `Group`;

ومع ذلك فإنه لا يعمل في PostgreSQL وربما بعض المنصات الأخرى.

في PostgreSQL يمكنك استخدام جملة DISTINCT ON :

SELECT DISTINCT ON ("group") * FROM "mytable" ORDER BY "group", "age" DESC;

لست متأكدا إذا كان MySQL يحتوي على دالة row_number. إذا كان الأمر كذلك يمكنك استخدامه للحصول على النتيجة المرجوة. على SQL Server يمكنك القيام بشيء مشابه لـ:

CREATE TABLE p
(
 person NVARCHAR(10),
 gp INT,
 age INT
);
GO
INSERT  INTO p
VALUES  ('Bob', 1, 32);
INSERT  INTO p
VALUES  ('Jill', 1, 34);
INSERT  INTO p
VALUES  ('Shawn', 1, 42);
INSERT  INTO p
VALUES  ('Jake', 2, 29);
INSERT  INTO p
VALUES  ('Paul', 2, 36);
INSERT  INTO p
VALUES  ('Laura', 2, 39);
GO

SELECT  t.person, t.gp, t.age
FROM    (
         SELECT *,
                ROW_NUMBER() OVER (PARTITION BY gp ORDER BY age DESC) row
         FROM   p
        ) t
WHERE   t.row = 1;

لن أستخدم Group as column name لأنها كلمة محجوزة. لكن بعد SQL ستعمل.

SELECT a.Person, a.Group, a.Age FROM [TABLE_NAME] a
INNER JOIN 
(
  SELECT `Group`, MAX(Age) AS oldest FROM [TABLE_NAME] 
  GROUP BY `Group`
) b ON a.Group = b.Group AND a.Age = b.oldest

هناك طريقة بسيطة للغاية للقيام بذلك في mysql:

select * 
from (select * from mytable order by `Group`, age desc, Person) x
group by `Group`

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

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

ملاحظة: هذا هو الحل mysql فقط . جميع قواعد البيانات الأخرى التي أعرفها ستلقي خطأ في بناء جملة SQL مع الرسالة "لا يتم سرد الأعمدة غير المجمعة في المجموعة حسب العبارة" أو ما شابه ذلك. نظرًا لأن هذا الحل يستخدم سلوكًا غير موثَّق ، فقد يرغب أكثر حذراً في تضمين اختبار لتأكيد أنه سيظل يعمل في حالة تغيير إصدار مستقبلي من MySQL هذا السلوك.

تحديث الإصدار 5.7:

منذ الإصدار 5.7 ، يتضمن إعداد sql-mode ONLY_FULL_GROUP_BY بشكل افتراضي ، لذلك لجعل هذا العمل يجب أن لا يكون لديك هذا الخيار (قم بتحرير ملف الخيار للخادم لإزالة هذا الإعداد).


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

SELECT SUBSTRING_INDEX(GROUP_CONCAT(column_x ORDER BY column_y),',',1) AS xyz,
   column_z
FROM table_name
GROUP BY column_z;

تستخدم GROUP_CONCAT لإنشاء قائمة concat مرتبة ، ثم أقوم بسلسلة فرعية فقط.


يمكنك الانضمام ضد طلب فرعي يسحب MAX(Group) Age . هذه الطريقة المحمولة عبر معظم RDBMS.

SELECT
  yourtable.*
FROM
  yourtable
  JOIN (
    SELECT `Group`, MAX(Age) AS age
    FROM yourtable 
    GROUP BY `Group`
  ) maxage
     /* join subquery against both Group and Age values */
     ON yourtable.`Group` = maxage.`Group` 
        AND yourtable.Age = maxage.age

with CTE as 
(select Person, 
[Group], Age, RN= Row_Number() 
over(partition by [Group] 
order by Age desc) 
from yourtable)`


`select Person, Age from CTE where RN = 1`




greatest-n-per-group