문제
기존 응용 프로그램에 기능을 추가하려고 노력하고 있으며 MySQL보기를 발견했습니다.
SELECT
AVG(table_name.col1),
AVG(table_name.col2),
AVG(table_name.col3),
table_name.personID,
table_name.col4
FROM table_name
GROUP BY table_name.personID;
좋아, 몇 가지 집계 기능이 있습니다. 당신은 그것에 의해 그룹화되고 있기 때문에 personID를 선택할 수 있습니다. 그러나 그것은 또한 집계 함수가 아닌 열을 선택하고 있으며 절에 의해 그룹의 일부가 아닙니다. 이것이 어떻게 가능한지??? 그룹당 값이 고유하지 않기 때문에 임의의 값을 선택합니까?
내가 (MSSQL Server)에서 온 곳은 오류입니다. 누군가 나 에게이 행동을 설명하고 왜 MySQL에서 허용되는지 설명 할 수 있습니까?
해결책
이 기능이 일부 모호한 쿼리를 허용하고 해당 열에서 선택한 임의의 값으로 결과 세트를 조용히 반환합니다. 실제로, 그것은 먼저 물리적으로 저장된 그룹 내 행의 값 인 경향이 있습니다.
이 쿼리는 기준에 따라 그룹의 열에 기능적으로 의존하는 열만 선택하는 경우 모호하지 않습니다. 다시 말해, 그룹을 정의하는 값 당 "모호한"열의 뚜렷한 값만있을 수 있다면 아무런 문제가 없습니다. 이 쿼리는 Microsoft SQL Server (및 ANSI SQL)에서 불법이지만 논리적으로 모호성을 초래할 수는 없습니다.
SELECT AVG(table1.col1), table1.personID, persons.col4
FROM table1 JOIN persons ON (table1.personID = persons.id)
GROUP BY table1.personID;
또한 MySQL은 표준에 따라 작동하게하는 SQL 모드를 가지고 있습니다. ONLY_FULL_GROUP_BY
fwiw, sqlite는 또한이 모호한 그룹을 조항으로 허용하지만, 그것은 마지막 그룹에서 행.†
† 적어도 내가 테스트 한 버전에서. 그것이 의미하는 바 임의 MySQL 또는 Sqlite는 미래에 구현을 변경하고 다른 동작을 가질 수 있다는 것입니다. 그러므로 당신은 현재 이와 같은 모호한 경우에있는 행동에 의존해서는 안됩니다. 쿼리를 결정 론적이고 모호하지 않도록 다시 작성하는 것이 좋습니다. 그렇기 때문에 MySQL 5.7은 이제 기본적으로 hone_full_group_by를 활성화합니다.
다른 팁
조금만 더 구글을봤을 것입니다 ... 내가 찾은 것 같습니다. 내 대답.
MySQL은 그룹별로 표시되지 않는 선택 목록에서 응집되지 않은 열 또는 계산을 사용할 수 있도록 그룹의 사용을 확장합니다. 불필요한 열 정렬 및 그룹화를 피 함으로써이 기능을 사용하여 더 나은 성능을 얻을 수 있습니다. 예를 들어, 다음 쿼리에서 고객을 그룹화 할 필요가 없습니다.
표준 SQL에서는 Customer.Name을 그룹에 의해 추가해야합니다. MySQL에서는 이름이 중복됩니다.
그래도, 그것은 단지 ... 틀린 것 같습니다.
select * from personel where p_id IN(select
min(dbo.personel.p_id)
FROM
personel
GROUP BY dbo.personel.p_adi)
다음과 같은 쿼리가 있다고 가정 해 봅시다.
SELECT g, v
FROM t
GROUP BY g;
이 경우, 가능한 각 가능한 값에 대해 g
, MySQL은 해당 값 중 하나를 선택합니다 v
.
그러나 선택된 것은 어떤 상황에 달려 있습니다.
나는 각 G 그룹에 대해 첫 번째 값을 읽었습니다. v
레코드가 테이블에 어떻게 삽입되었는지 순서대로 유지됩니다. t
.
테이블의 기록이 세트 요소의 순서가 중요하지 않은 곳. 이것은 "mysql-ish"입니다 ...
어떤 값을 결정하려면 v
유지하려면 SubSelect를 신청해야합니다. t
이와 같이:
SELECT g, v
FROM (
SELECT *
FROM t
ORDER BY g, v DESC
) q
GROUP BY g;
이렇게하면 하위 쿼리의 레코드가 외부 쿼리에 의해 처리되는 순서를 정의하므로 어떤 값을 신뢰할 수 있습니다. v
개별 값을 선택합니다 g
.
그러나 조건이 필요한 경우 매우 조심하십시오. 위치 조건을 하위 쿼리에 추가하면 동작을 유지하면 항상 예상되는 값을 반환합니다.
SELECT g, v
FROM (
SELECT *
FROM t
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
GROUP BY g;
이것이 당신이 기대하는 것, 서브 선택 필터와 테이블을 주문합니다. 그것은 기록을 어디에 보관합니다 g
주어진 값이 있고 외부 쿼리는 다음을 반환합니다. g
그리고 첫 번째 가치 v
.
그러나 외부 쿼리에 동일한 위치 조건을 추가하면 결정적이지 않은 결과가 나타납니다.
SELECT g, v
FROM (
SELECT *
FROM t
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g;
놀랍게도, 당신은 다른 값을 얻을 수 있습니다 v
같은 쿼리를 계속해서 실행할 때 ... 이상합니다. 예상되는 동작은 하위 쿼리에서 모든 레코드를 적절한 순서로 가져 와서 외부 쿼리에서 필터링 한 다음 이전 예제에서 선택한 것과 동일하게 선택하는 것입니다. 그러나 그렇지 않습니다.
그것은 값을 선택합니다 v
무작위로 겉보기에. 동일한 쿼리가 다른 값을 반환했습니다 v
더 많은 시간 (~ 20)을 실행했지만 분포가 균일하지 않은 경우.
외부를 추가하는 대신 다음과 같은 조건을 지정합니다.
SELECT g, v
FROM (
SELECT *
FROM t1
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g
HAVING g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9';
그런 다음 다시 일관된 행동을 얻습니다.
결론 : 나는이 기술에 전혀 의존하지 않는 것이 좋습니다. 정말로 원하거나 필요한 경우 외부 쿼리의 조건을 피하십시오. 외부 쿼리에 할 수 있거나 절차가있는 경우 내부 쿼리에 사용하십시오.
이 데이터로 테스트했습니다.
CREATE TABLE t1 (
v INT,
g VARCHAR(36)
);
INSERT INTO t1 VALUES (1, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
INSERT INTO t1 VALUES (2, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
MySQL 5.6.41에서.
어쩌면 새로운 버전으로 수정 된 버그 일 수도 있습니다. 최신 버전에 대한 경험이있는 경우 피드백을 제공하십시오.