2015-10-23 3 views
2

Если столбец в предложении SELECT не указан в предложении GROUP BY, группа SQLite по остальным столбцам (по умолчанию), а затем возвращает значение опущенного столбца в первой строке, которую он оценивает ?поведение группы SQLite

Например, найти TransactionID, связанный с наивысшим значением за ProductID:

CREATE TABLE IF NOT EXISTS ProductTransaction 
(
    Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
    ProductId INTEGER NOT NULL, 
    TransactionType INTEGER NOT NULL, 
    Value INTEGER NOT NULL 
); 

INSERT INTO ProductTransaction (ProductId, TransactionType, Value) 
VALUES (1, 7, 23), (1, 3, 12), (2, 4, 43), (1, 7, 5), (1, 10, 23), 
(3, 3, 23), (3, 2, 31), (1, 1, 23), (2, 5, 50), (2, 6, 14), (1, 4, 23); 

SELECT ProductId 
, TransactionType 
, MAX(Value) 
FROM ProductTransaction 
GROUP BY ProductId; 

DELETE FROM ProductTransaction; 

Running предыдущие заявления дает мне TransactionType из 7 для PRODUCTID 1 (максимальное значение 23).

Однако, если добавить индекс:

CREATE INDEX IF NOT EXISTS IDX_TransType ON ProductTransaction(ProductId ASC, TransactionType ASC); 

Он возвращает TransactionType 1, по-видимому, потому, что теперь приказывать строки по индексу. Изменение индекса поддерживает эту теорию:

CREATE INDEX IF NOT EXISTS IDX_TransType ON ProductTransaction(ProductId ASC, TransactionType DESC); 

Он теперь будет возвращать TransactionType 10 для PRODUCTID 1.

Является ли это поведение конструкции, или это просто ненадежный побочный эффект?

EDIT: Кажется, что это ненадежный побочный эффект. Из документации:

Каждое выражение в результирующем наборе затем оценивается один раз для каждой группы строк . Если выражение является агрегированным выражением, оно равно , которое оценивается по всем строкам в группе. В противном случае оценивается против одной произвольно выбранной строки из группы. Если существует более одного неагрегатного выражения в результирующем наборе, , тогда все такие выражения оцениваются для одной и той же строки.

https://www.sqlite.org/lang_select.html#resultset

+1

'TransactionType' не является ни частью' GROUP BY', ни использоваться в агрегатной функции, поэтому какая строка SQLite использует для результат «TransactionType» не указан. –

ответ

2

Так как SQLite 3.7.11, используя MAX() или MIN() заставят любые необобщенные столбцы поступать из одной и той же строки, что соответствует МАХУ()/MIN().

Однако, если существует несколько строк с тем же самым большим/маленьким значением, то по-прежнему не указано, из какой из этих строк поступают значения других столбцов. (Поведение SQLite в этом отношении непротиворечиво, но может изменяться в разных версиях или с различными схемами базы данных.)

Смежные вопросы