รายการที่เลือกไม่อยู่ในคำสั่ง GROUP BY และมีคอลัมน์ที่ไม่รวม ... เข้ากันไม่ได้กับ sql_mode = only_full_group_by


144

AM ใช้ MySQL 5.7.13 บนพีซีที่ใช้ Windows กับเซิร์ฟเวอร์ WAMP

นี่คือปัญหาของฉันในขณะที่เรียกใช้แบบสอบถามนี้

SELECT *
FROM `tbl_customer_pod_uploads`
WHERE `load_id` = '78' AND
      `status` = 'Active'
GROUP BY `proof_type`

ฉันมักจะได้รับข้อผิดพลาดเช่นนี้

นิพจน์ # 1 ของรายการ SELECT ไม่ได้อยู่ใน GROUP BY clause และมีคอลัมน์ที่ไม่รวม 'returntr_prod.tbl_customer_pod_uploads.id' ซึ่งไม่ได้ขึ้นอยู่กับคอลัมน์ใน GROUP BY clause สิ่งนี้เข้ากันไม่ได้กับ sql_mode = only_full_group_by

คุณช่วยบอกทางออกที่ดีที่สุดได้ไหม ...

ฉันต้องการผลลัพธ์เช่น

+----+---------+---------+---------+----------+-----------+------------+---------------+--------------+------------+--------+---------------------+---------------------+
| id | user_id | load_id | bill_id | latitude | langitude | proof_type | document_type | file_name    | is_private | status | createdon           | updatedon           |
+----+---------+---------+---------+----------+-----------+------------+---------------+--------------+------------+--------+---------------------+---------------------+
|  1 |       1 | 78      | 1       | 21.1212  | 21.5454   |          1 |             1 | id_Card.docx |          0 | Active | 2017-01-27 11:30:11 | 2017-01-27 11:30:14 |
+----+---------+---------+---------+----------+-----------+------------+---------------+--------------+------------+--------+---------------------+---------------------+

14
อย่าใช้SELECT *.
shmosel


กำลังพูดเช่นนี้ SELECT id FROM tbl_customer_pod_uploadsWHERE load_id= '78' AND status= 'Active' GROUP BYproof_type
Dhanu K

2
หากคุณต้องการความเข้ากันได้สำหรับแบบสอบถามเก่าคุณสามารถปิดonly_full_group_byโหมด SQL ได้
Barmar

5
ลองใช้ ANY_VALUE (proof_type): dev.mysql.com/doc/refman/5.7/en/group-by-handling.html SELECT *, ANY_VALUE (proof_type) FROM tbl_customer_pod_uploadsWHERE load_id= '78' AND status= 'Active' GROUP BYproof_type
AlexGach

คำตอบ:


278

นี้

นิพจน์ # 1 ของรายการ SELECT ไม่ได้อยู่ใน GROUP BY clause และมีคอลัมน์ที่ไม่รวม 'returntr_prod.tbl_customer_pod_uploads.id' ซึ่งไม่ได้ขึ้นอยู่กับคอลัมน์ใน GROUP BY clause สิ่งนี้เข้ากันไม่ได้กับ sql_mode = only_full_group_by

จะแก้ไขได้ง่ายๆโดยการเปลี่ยนโหมด sql ใน MySQL ด้วยคำสั่งนี้

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

สิ่งนี้ใช้ได้กับฉันเช่นกัน .. ฉันใช้สิ่งนี้เพราะในโปรเจ็กต์ของฉันมี Queries มากมายเช่นนี้ดังนั้นฉันจึงเปลี่ยนโหมด sql นี้เป็น only_full_group_by

ขอขอบคุณ... :-)


14
มันใช้ได้กับฉัน!. คุณช่วยวันของฉัน อย่าลืมรีสตาร์ท MYSQL SERVICE
marcode_ely

2
หากฉันใช้ Codeigniter และฉันต้องการรันในโมเดลฉันจะใช้มันอย่างไร? สามารถช่วยฉัน? @marcode_ely
DhavalThakor

@DhavalThakor เมื่อคุณเรียกใช้แบบสอบถามนี้ในเซิร์ฟเวอร์ของคุณคุณไม่จำเป็นต้องเรียกใช้ซ้ำแล้วซ้ำอีก ดังนั้นคุณไม่จำเป็นต้องใส่ไว้ในแบบจำลองของคุณ
Dhanu K

2
MySQL 5.7.29 ไม่จำเป็นต้องเริ่มบริการใหม่
Taavi

2
ฉันใช้เวอร์ชันเซิร์ฟเวอร์: 5.7.31-0ubuntu0.16.04.1 - (Ubuntu) และเมื่อใดก็ตามที่ฉันสตาร์ทเครื่องฉันตั้งค่าทุกครั้งมีการแก้ไขถาวรสำหรับสิ่งนี้หรือไม่
Arpita Hunka

87

เมื่อของ MySQL only_full_group_byโหมดเปิดอยู่ก็หมายความว่ากฎระเบียบที่เข้มงวด ANSI SQL GROUP BYจะใช้เมื่อมีการใช้ สำหรับคำถามของคุณนั่นหมายความว่าหากคุณGROUP BYอยู่ในproof_typeคอลัมน์คุณสามารถเลือกได้สองสิ่งเท่านั้น:

  • proof_typeคอลัมน์หรือ
  • ผลรวมของคอลัมน์อื่น ๆ


โดย "มวล" คอลัมน์อื่น ๆ ผมหมายถึงการใช้ฟังก์ชันการรวมเช่นMIN(), MAX()หรือAVG()กับคอลัมน์อื่น ดังนั้นในกรณีของคุณแบบสอบถามต่อไปนี้จะถูกต้อง:

SELECT proof_type,
       MAX(id) AS max_id,
       MAX(some_col),
       MIN(some_other_col)
FROM tbl_customer_pod_uploads
WHERE load_id = '78' AND
      status = 'Active'
GROUP BY proof_type

GROUP BYคำถามMySQL ส่วนใหญ่ที่ฉันเห็นใน SO นั้นปิดโหมดเข้มงวดดังนั้นการสืบค้นจึงทำงาน แต่มีผลลัพธ์ที่ไม่ถูกต้อง ในกรณีของคุณการสืบค้นจะไม่ทำงานเลยบังคับให้คุณคิดเกี่ยวกับสิ่งที่คุณต้องการทำจริงๆ

หมายเหตุ: ANSI SQL จะขยายสิ่งที่ได้รับอนุญาตให้เลือกGROUP BYโดยการรวมคอลัมน์ซึ่งขึ้นอยู่กับฟังก์ชันที่เลือกไว้ ตัวอย่างของการพึ่งพาการทำงานจะถูกจัดกลุ่มตามคอลัมน์คีย์หลักในตาราง เนื่องจากคีย์หลักได้รับการรับรองว่าไม่ซ้ำกันสำหรับทุกระเบียนดังนั้นจึงมีการกำหนดค่าของคอลัมน์อื่นด้วย MySQL เป็นหนึ่งในฐานข้อมูลที่อนุญาตสำหรับสิ่งนี้ (SQL Server และ Oracle ไม่ใช่ AFAIK)


2
หมายเหตุเพียงข้อเดียว: ผลลัพธ์ไม่ถูกต้อง (เป็นไปตามกฎของ MySQL) แต่ไม่สามารถคาดเดาได้หมายความว่าคอลัมน์ที่ไม่ได้เป็นส่วนหนึ่งของกลุ่มตามและไม่รวม (และไม่ขึ้นอยู่กับฟังก์ชัน) จะส่งคืนค่า 'สุ่ม' จากกลุ่มที่เกี่ยวข้อง ตามที่คู่มือระบุ: "เซิร์ฟเวอร์มีอิสระในการเลือกค่าใด ๆ จากแต่ละกลุ่ม"
ทำนาย

การละเมิดการจัดกลุ่มที่เข้มงวดไม่จำเป็นต้องให้ผลลัพธ์ที่ไม่ถูกต้องเสมอไป ฉันมักจะทำเมื่อรับประกันว่าฟิลด์จะเหมือนกัน (เช่นการรวมแบบหนึ่งต่อหลาย) และแม้ว่าจะไม่รับประกันการเลือกแถวตามอำเภอใจก็มักจะไม่ผิดอีกต่อไปจากนั้นใช้ฟังก์ชันรวมหรือเพิ่มระดับการจัดกลุ่ม
shmosel

1
+1 สำหรับฉัน ฉันไม่รู้ว่าทำไมคำตอบที่ "ยอมรับ" ข้างต้นจึงได้รับการยอมรับ วิธีของคุณเป็นวิธีที่ถูกต้องและคำตอบที่ได้รับการยอมรับคือการแก้ไขปัญหาแฮ็กกี้ตามปกติซึ่งจะนำไปสู่ปัญหาเพิ่มเติมในอนาคต
Jcov

1
@Jcov ... และฉันไม่เห็นด้วยกับความคิดเห็นของคุณอีก +1 การปิดการ จำกัด ANSI GROUP BYเป็นความคิดที่ไม่ดี ทำให้ฉันกลัวที่ผู้ใช้จำนวนมากใช้คำแนะนำที่ไม่ถูกต้องและใช้มัน
ทิมบีเกไลเซน

1
@TimBiegeleisen ยินดีต้อนรับสู่การพัฒนาคัดลอกและวางที่ทันสมัย "ฉันไม่จำเป็นต้องคิดว่ามีคนที่อ่านสิ่งที่สุ่มจากแหล่งที่ไม่น่าเชื่อถือได้คิดให้ฉันแล้ว"
Jcov

53

ใช้วิธีใดวิธีหนึ่ง

(1) PHPMyAdmin

หากคุณใช้ phpMyAdmin ให้เปลี่ยนการตั้งค่า " sql_mode " ตามที่ระบุไว้ในภาพหน้าจอด้านล่าง ใส่คำอธิบายภาพที่นี่

แก้ไขตัวแปร "sql mode" และลบข้อความ "ONLY_FULL_GROUP_BY" ออกจากค่า

(2) SQL / Command prompt เรียกใช้คำสั่งด้านล่าง

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

(3) อย่าใช้ SELECT *

ใช้คอลัมน์ที่เกี่ยวข้องในแบบสอบถาม SELECT ที่เกี่ยวข้องหมายถึงคอลัมน์ซึ่งมาใน "กลุ่มตาม" อนุประโยคหรือคอลัมน์ที่มีฟังก์ชันการรวม (MAX, MIN, SUM, COUNT ฯลฯ )


โน๊ตสำคัญ

การเปลี่ยนแปลงที่ทำโดยใช้จุด (1) หรือจุด (2) จะไม่ถูกตั้งค่าไว้อย่างถาวรและจะเปลี่ยนกลับหลังจากรีสตาร์ททุกครั้ง

ดังนั้นคุณควรตั้งค่านี้ในไฟล์กำหนดค่าของคุณ (เช่น /etc/mysql/my.cnf ในส่วน [mysqld]) เพื่อให้การเปลี่ยนแปลงยังคงมีผลหลังจาก MySQL รีสตาร์ท:

ไฟล์กำหนดค่า : /etc/mysql/my.cnf

ชื่อตัวแปร : sql_mode หรือ sql-mode


ขอบคุณมากสำหรับคำตอบข้างต้น ฉันต้องการเปลี่ยนสิ่งนี้ตามที่คุณพูดใน my.cnf แต่เมื่อฉันเปิดไฟล์นั้นไฟล์นั้นจะเปิดในโหมดอ่านอย่างเดียวเท่านั้น ลิงก์ช่วยเหลือหรืออ้างอิงใด ๆ ???. ฉันใช้ Ubuntu 16.04
Sanmitha Sadhishkumar

1
(1) เปลี่ยนการอนุญาตไฟล์ของไฟล์ my.cnf โดยใช้คำสั่ง "chmod" (2) ทำการเปลี่ยนแปลงใน my.cnf (3) ตั้งค่าเป็นแบบอ่านอย่างเดียวอีกครั้ง (เปลี่ยนการอนุญาตไฟล์อีกครั้งโดยใช้ "chmod") (4) รีสตาร์ท mysql
Rakesh Soni

23

วิธีการด้านล่างแก้ปัญหาของฉัน:

ใน Ubuntu

ประเภท: sudo vi /etc/mysql/my.cnf

พิมพ์ A เพื่อเข้าสู่โหมดแทรก

ในบรรทัดสุดท้ายวางใต้รหัสสองบรรทัด:

[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

พิมพ์ esc เพื่อออกจากโหมดอินพุต

Type :wq to save and close vim.

พิมพ์sudo service mysql restartเพื่อรีสตาร์ท MySQL


1
ขอบคุณมันได้ผล! ในระบบปฏิบัติการ cent, whm, my.cnf ตั้งอยู่ที่ sudo vi
/etc/my.cnf

21

คุณสามารถปิดการใช้งาน sql_mode = only_full_group_by โดยคำสั่งบางอย่างที่คุณสามารถลองใช้โดยเทอร์มินัลหรือ MySql IDE

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

12

ใน Ubuntu

ขั้นตอนที่ 1:

sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf

ขั้นตอนที่ 2: ไปที่บรรทัดสุดท้ายและเพิ่มสิ่งต่อไปนี้

sql_mode = ""

ขั้นตอนที่ 3: บันทึก

ขั้นตอนที่ 4: รีสตาร์ทเซิร์ฟเวอร์ mysql


9

เพื่อให้แบบสอบถามเป็นกฎหมายใน SQL92 คอลัมน์ชื่อต้องถูกละเว้นจากรายการที่เลือกหรือตั้งชื่อในส่วนคำสั่ง GROUP BY

SQL99 และใหม่กว่าอนุญาตให้มีการไม่รวมดังกล่าวต่อคุณลักษณะที่เป็นทางเลือก T301 หากฟังก์ชันเหล่านี้ขึ้นอยู่กับคอลัมน์ GROUP BY: หากมีความสัมพันธ์ดังกล่าวระหว่าง name และ custid การสืบค้นจะถูกต้องตามกฎหมาย ในกรณีนี้ตัวอย่างเช่นมีการดูแลคีย์หลักของลูกค้า

MySQL 5.7.5 ขึ้นไปดำเนินการตรวจจับการพึ่งพาการทำงาน หากเปิดใช้งานโหมด ONLY_FULL_GROUP_BY SQL (ซึ่งเป็นค่าเริ่มต้น) MySQL จะปฏิเสธการสืบค้นที่รายการที่เลือกเงื่อนไข HAVING หรือรายการ ORDER BY อ้างถึงคอลัมน์ที่ไม่ได้รวมที่ไม่มีชื่อในส่วนคำสั่ง GROUP BY หรือไม่ขึ้นอยู่กับฟังก์ชัน .

ผ่านMySQL :: MySQL 5.7 คู่มืออ้างอิง :: 12.19.3 การจัดการ MySQL ของ GROUP BY

คุณสามารถแก้ได้โดยเปลี่ยนโหมด sql ด้วยคำสั่งนี้:

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

และ ... อย่าลืมเชื่อมต่อฐานข้อมูลอีกครั้ง !!!


7

only_full_group_by = onบอก MySQL engine: อย่าใช้GROUP BYเมื่อคุณมีข้อสงสัยเกี่ยวกับผลลัพธ์ที่จะแสดงและทำให้เกิดข้อผิดพลาด ใช้มันก็ต่อเมื่อคำสั่งนั้นบอกคุณโดยเฉพาะว่าต้องทำอะไร เช่นเมื่อคำสั่งเต็มและสมบูรณ์!

only_full_group_by = offบอก MySQL engine: ใช้เสมอGROUP BYและหากคุณมีข้อสงสัยเกี่ยวกับผลลัพธ์ที่จะเลือกเพียงเลือกแบบสุ่ม!

คุณจะไม่ปิดถ้าคุณใช้ GROUP BYอย่างถูกต้อง!

ตัวอย่าง:

ตาราง: ผู้ใช้

 id   |  name
----------------
  1      ali
  2      john
  3      ali

เมื่อคุณใช้GROUP BYในnameคอลัมน์:

SELECT * FROM users GROUP BY name;

มีสองผลลัพธ์ที่เป็นไปได้:

  1      ali
  2      john     

หรือ

  2      john
  3      ali

MYSQL ไม่รู้จะเลือกผลอะไร! เนื่องจากมีids ที่แตกต่างกันแต่ทั้งสองมีname=ali.

โซลูชันที่ 1:

เลือกเฉพาะnameฟิลด์:

SELECT name FROM users GROUP BY name;

ผลลัพธ์:

  ali
  john     

นี่เป็นทางออกที่สมบูรณ์แบบ ลบคอลัมน์ที่ทำให้GROUP BYสับสน ซึ่งหมายความว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่ โดยปกติคุณไม่จำเป็นต้องใช้
คอลัมน์เหล่านั้น แต่ถ้าคุณต้องการให้ไปที่ solution3!

โซลูชัน 2:

only_full_group_byปิด MYSQL จะแสดงหนึ่งในสองผลลัพธ์ที่เป็นไปได้แบบสุ่ม !! (ไม่เป็นไรถ้าคุณไม่สนใจว่าidมันจะเลือกอะไร)

โซลูชัน 3

ใช้Aggregateฟังก์ชั่นเช่นMIN(), MAX()ความช่วยเหลือ MYSQL ที่จะตัดสินใจว่าจะต้องเลือก

ตัวอย่างเช่นฉันต้องการขั้นต่ำid:

SELECT MIN(id), name FROM users GROUP BY name;

ผลลัพธ์:

  1      ali
  2      john     

มันจะเลือกแถวซึ่งมีขั้นต่ำaliid


5

ไปที่ phpmyadmin และเปิดคอนโซลและดำเนินการตามคำขอนี้

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

5

ANY_VALUE(column_name)สวัสดีแทนการคอลัมน์ทั้งหมดใช้เวลาเพียงแค่สิ่งที่คุณต้องการโดยใช้ มันทำงานได้อย่างสมบูรณ์ เพียงแค่ตรวจสอบ

เช่น:

SELECT proof_type,any_value("customer_name") as customer_name
FROM `tbl_customer_pod_uploads`
WHERE `load_id` = '78' AND `status` = 'Active' GROUP BY `proof_type`


3

ค้นหา "โหมด SQL" หากคุณใช้ PhpMyAdmin และถอดค่าออก: ONLY_FULL_GROUP_BYก็ทำได้และใช้ได้


2

จากลักษณะที่ปรากฏฉันคิดว่าการจัดกลุ่มตามหลายคอลัมน์ / ฟิลด์จะไม่ส่งผลเสียต่อผลลัพธ์ของคุณ ทำไมคุณไม่ลองเพิ่มลงในกลุ่มโดยทำดังนี้:

GROUP BY `proof_type`, `id`

ซึ่งจะจัดกลุ่มตามลำดับproof_typeก่อนidหลัง ฉันหวังว่าสิ่งนี้จะไม่เปลี่ยนแปลงผลลัพธ์ ในบางกรณี / ส่วนใหญ่จัดกลุ่มตามหลายคอลัมน์ให้ผลลัพธ์ที่ไม่ถูกต้อง


1
  1. เข้าสู่ระบบ phpMyAdmin
  2. ไปที่: Server: localhost: 3306 และไม่เลือกฐานข้อมูลใด ๆ
  3. คลิกตัวแปรจากเมนูด้านบน
  4. ค้นหา "sql mode" และแก้ไขค่าที่เกี่ยวข้องเป็น: NO_ENGINE_SUBSTITUTION

นั่นคือทั้งหมด

ฉันทำสิ่งนี้ใน Ec2 ของฉันและมันได้ผลเหมือนมีเสน่ห์


1

นี่เป็นวิธีที่ง่ายและรวดเร็วในการตั้งค่าอย่างถาวร

หมายเหตุ: การทำงานSET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','')); เป็นแบบชั่วคราวและเมื่อรีสตาร์ทเซิร์ฟเวอร์คุณจะยังคงพบข้อผิดพลาด ในการแก้ไขปัญหานี้อย่างถาวรให้ทำดังต่อไปนี้

  1. เข้าสู่ระบบเซิร์ฟเวอร์ของคุณในฐานะรูท
  2. ในการรันเทอร์มินัลของคุณ wget https://gist.githubusercontent.com/nfourtythree/90fb8ef5eeafdf478f522720314c60bd/raw/disable-strict-mode.sh
  3. ทำให้สคริปต์ทำงานได้โดยการรัน chmod +x disable-strict-mode.sh
  4. รันสคริปต์โดยรัน ./disable-strict-mode.sh

และเสร็จแล้วการเปลี่ยนแปลงจะเกิดขึ้นกับ mysql และจะเริ่มต้นใหม่


1

ฉันมีปัญหาคล้ายกันกับส่วนหนึ่งของฐานข้อมูลของฉันบด สิ่งที่ฉันทำคือฉันเปลี่ยนพารามิเตอร์ใน DB ผ่านคอนโซลฐานข้อมูล PHPStorm ดังนี้:

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

ใช้งานได้เหมือนมีเสน่ห์ในขณะนี้


0

อัปเดตสำหรับ MySQL 8.0

ของคุณsql-modeจะไม่มีNO_AUTO_CREATE_USERเนื่องจากถูกลบออกไปแล้วตามที่กล่าวไว้นี้ - วิธีการตั้งค่า sql-mode-in-my-cnf-in-mysql-8

[mysqld]
sql-mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"

นอกจากนี้หากใครไม่มีmy.cnfไฟล์ก็จะสร้างไฟล์ใหม่/etc/my.cnfจากนั้นเพิ่มบรรทัดด้านบน


-2

ในของคุณmy.iniเขียนสิ่งนี้:

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

ขึ้นอยู่กับรุ่นของคุณ หรือ:

[mysqld]
sql_mode = ""

หรือเพียงแค่ลบสิ่งนี้: ONLY_FULL_GROUP_BY


-2

เปิดพาเนล WAMP และเปิดไฟล์คอนฟิกูเรชัน MySQL ในนั้นให้ค้นหา "sql_mode" หากคุณพบว่าตั้งค่าเป็น "" else หากคุณไม่พบว่าจะเพิ่ม sql_mode = "" ลงในไฟล์

รีสตาร์ทเซิร์ฟเวอร์ MySQL แล้วคุณก็พร้อม ...

มีความสุขในการเข้ารหัส

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.