簡體   English   中英

當 sql_mode=only_full_group_by 時,在 mysql 中完成 Group By 工作的最佳方法是什么

[英]What is the best way to do the job of Group By in mysql when sql_mode=only_full_group_by

我想執行一個查詢,例如在我的本地主機上獲取 DB 中任何類型的最后一條記錄,我使用 Maria Db,查詢如下:

SELECT * 
  FROM table_a
 WHERE column_a=999
    OR column_b=999 
 GROUP 
    BY `group`;

group是我在其中保存類型的列,例如:營銷、博客、訂單等

此查詢在本地運行良好,但在服務器上我收到以下錯誤:

SQLSTATE[42000]: 
Syntax error or access violation: 
1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'db_name.table_a.id' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by\n
The SQL being executed was: 
SELECT * FROM `table_a` WHERE (`column_a`=999) OR (`column_b`=999) GROUP BY `group`"

根據MySQL 文檔,我可以使用以下命令來實現這一點:

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

但我對 Db 沒有足夠的權限並收到以下錯誤:

#1227 - Access denied; you need (at least one of) the SUPER privilege(s) for this operation

我讓主機幫我做這件事,他們回答說他們不想做這個動作

我使用 YII2 框架,現在我想要一種方法將其添加到框架的 database_config.php 選項中,或者將查詢更改為具有相同結果的其他內容,並且不會損失性能

ONLY_FULL_GROUP_BY一件好事,它強制執行基本的 ANSI SQL 規則。 不要更改它,而是修復您的代碼。

從那里開始:你想要整個記錄,所以你不應該考慮聚合,而是過濾

然后:在數據庫表中,記錄是無序的; 為了使您的問題有意義,您需要一個定義每個組中行的順序的列,因此“最后”記錄的含義是明確的。 讓我假設您有這樣的列,稱為id

以下是此 top-1-per-group 問題的典型方法,使用相關子查詢進行過濾:

SELECT * 
FROM table_a a
WHERE 
    999 IN (column_a, column_b)
    AND id = (
        SELECT MAX(a1.id) 
        FROM table_a a1 
        WHERE 999 IN (a1.column_a, a1.column_b) AND a1.grp = a.grp
    )

或者,如果您正在運行 MySQL 8.0,則可以使用 window 函數:

SELECT *
FROM (
    SELECT a.*,
        ROW_NUMBER() OVER(PARTITION BY grp ORDER BY id DESC) rn
    FROM table_a a
    WHERE 999 IN (column_a, column_b)
) a
WHERE rn = 1

旁注: group是語言關鍵字,因此列名的選擇不佳。 我在查詢中將其重命名為grp

有幾種方法可以“繞過” sql_mode ,但請注意您得到的結果可能不正確。

首先,您可以使用ANY_VALUE() 像這樣的例子:

SELECT any_value(column_a), any_value(column_b), `group` FROM table_a 
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;

當使用ANY_VALUE() function 時,您必須將表中的SELECT和 append 中的所有列與您在GROUP BY中使用的 ANY_VALUE ANY_VALUE() ) 一起寫入列中。

使用 MAX() 或 MIN() 可以返回結果,但它仍然可能不是正確的結果,尤其是對於任何超過 1 個計數的行:

SELECT MAX(column_a), MAX(column_b), `group`
FROM table_a 
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;

使用GROUP_CONCAT可以讓您查看非分組列中的值。 將結果與上面的其他查詢進行比較,您可以在返回多個計數的行上看到,其他查詢是否根據您的需要返回?

SELECT group_concat(column_a), group_concat(column_b), group_concat(`group`)
FROM table_a 
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;

我不確定您是否可以這樣做,但您可以暫時關閉sql_mode ,然后您應該能夠運行您的查詢:

SET sql_mode=""; -- you don't need to set global privilege.
SELECT * FROM table_a 
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;

演示在這里

盡管如此,最好的選擇是保留sql_mode並根據要求構造查詢。

P/S: GROUPMySQLMariaDB中的保留字。 您可以將其用作列名,但您必須始終添加反引號來定義列,否則,運行查詢將返回一個錯誤,例如

查詢:select * from table_a group by group

錯誤代碼:1064 您的 SQL 語法有錯誤; 檢查與您的 MariaDB 服務器版本相對應的手冊,以獲得在第 1 行的“組”附近使用的正確語法

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM