ВЫБЕРИТЕ min строку каждой группы в SQLITE? - PullRequest
0 голосов
/ 05 декабря 2018

Допустим, я создал таблицу SQLITE из четырех значений TEXT first, last, street, state и двух значений INTEGER age, weight.Я хочу создать запрос, который будет ВЫБРАТЬ строку каждого first, last, street, state с самым низким age, используя weight для разрешения конфликтов, если две записи имеют одинаковые значения для всех first, last, street, state, age.

IЯ думаю, что могу сделать что-то похожее на это:

SELECT * FROM MyTable
GROUP BY first, last, street, state
ORDER BY age, weight

Но я почти уверен, что запрос, который я только что дал вам, собирается извлечь произвольную строку из каждой группы first, last, street, state, а затем отсортировать результаты по age, weight.Что мне нужно сделать, чтобы определить, какая строка из GROUP BY сохраняется?Я подумал, что вместо этого я мог бы сделать

SELECT first, last, street, state, MIN(age), MIN(weight) FROM MyTable
GROUP BY first, last, street, state

Но, конечно, это выберет минимальный возраст и минимальный вес, а не минимальный возраст, использующий вес в качестве тай-брейка.

ОБРАЗЕЦ ВХОДА:

first, last,    street,   state, age, weight
John   Doe      1 Elm     NY     50   120
John   Doe      1 Elm     NY     35   140
Mark   Knopfler 6 Strait  CT     67   130
Mary   West     32 E St   NJ     90   162
Mary   West     32 E St   NJ     55   120

ВЫБОР ВЫБОРА:

first, last,    street,   state, age, weight
John   Doe      1 Elm     NY     35   140
Mark   Knopfler 6 Strait  CT     67   130
Mary   West     32 E St   NJ     55   120

Затем я хотел бы пойти и удалить записи, которые я не выбрал в исходной таблице.Но я представляю, что это будет новый кошмар.(По сути, я хочу, чтобы таблица создавалась так, как если бы я создал ее с ограничением UNIQUE (first, last, street, State) и добавил строки по возрастанию и возрастанию веса. Это даст эквивалентный результат.)

1 Ответ

0 голосов
/ 05 декабря 2018

Я полагаю, что может подойти следующее: -

-- Select SQL
SELECT rowid, first, street, state, age, weight 
FROM mytable AS mt1
WHERE (age * 1000 + weight) = (
    SELECT min(age * 1000 + weight) 
    FROM mytable 
    WHERE first = mt1.first AND last = mt1.last AND street = mt1.street AND state = mt1.state
    ORDER BY (age,weight) ASC
    LIMIT 1
    )
  • Это сочетает в себе возраст и вес (но сохраняя индивидуальность каждого компонента для сравнения, следовательно, умножая возраст на 1000 (предполагает наивысший вес)будет меньше 1000, в противном случае потребуется большее число))
  • Предложение were сравнивает это значение с минимальным таким значением для того же первого, последнего, улицы и штата (нет необходимости в GROUP BY как выбранномвсе строки в соответствии с группой).

Тогда легко использовать это для удаления строк, не входящих в SELECT, используя (оберните запрос в предложении WITH как Общая таблицаВыражение (CTE) и затем использовать CTE (cte1) для запуска УДАЛЕНИЯ, чтобы удалить строки, чей rowid отсутствует в извлеченном списке rowid 's: -

-- Delete SQL
WITH cte1 AS
    (
        SELECT rowid, first, street, state, age, weight 
        FROM mytable AS mt1
        WHERE (age * 1000 + weight) = (
            SELECT min(age * 1000 + weight) 
            FROM mytable 
            WHERE first = mt1.first AND last = mt1.last AND street = mt1.street AND state = mt1.state
            ORDER BY (age,weight)
            LIMIT 1
        )
    )
DELETE FROM mytable WHERE rowid NOT IN (SELECT cte1.rowid FROM cte1)
;
  • Примечание предполагает, что таблица не является таблицей БЕЗ ROWID.

Тестирование

Выше было проверено с использованием следующего: -

-- Load testing data
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (first, last,    street,   state, age, weight);
INSERT INTO mytable VALUES
    ('John',   'Doe',      '1 Elm',     'NY',     50,   120),
    ('John',   'Doe',      '1 Elm',     'NY',     35,   140),
        ('John',   'Doe',      '1 Elm',     'NY',     35,   139),
    ('Mark',   'Knopfler', '6 Strait',  'CT',     67,   130),
    ('Mary',   'West',     '32 E St',   'NJ',     90,   88),
    ('Mary',   'West',     '32 E St',   'NJ',     55,   120), -- <<<<<<<<<< duplicated below
        ('Mary',   'West',     '32 E St',   'NJ',     55,   125),
        ('Mary',   'West',     '32 E St',   'NJ',     55,   124),
        ('Mary',   'West',     '32 E St',   'NJ',     55,   120), -- <<<<<<<<<< duplicate
        ('Mary',   'West',     '32 E St',   'NJ',     55,   121)
;
  • Обратите внимание, из вопроса неясно, должно ли быть какое-либо конкретное действиедля дублированных строк с наименьшим возрастом и весом (см. выделенные вставки выше)
    • В таком виде такие дубликаты останутся (не может существовать, если для объединенных столбцов было создано составное УНИКАЛЬНОЕ ограничение)

.

-- Show table before deletion
SELECT * FROM mytable;

-- Select SQL (not needed as embedded in delete below)
SELECT rowid, first, street, state, age, weight 
FROM mytable AS mt1
WHERE (age * 1000 + weight) = (
    SELECT min(age * 1000 + weight) 
    FROM mytable 
    WHERE first = mt1.first AND last = mt1.last AND street = mt1.street AND state = mt1.state
    ORDER BY (age,weight)
    LIMIT 1
    )
;

-- Delete SQL
WITH cte1 AS
    (
        SELECT rowid, first, street, state, age, weight 
        FROM mytable AS mt1
        WHERE (age * 1000 + weight) = (
            SELECT min(age * 1000 + weight) 
            FROM mytable 
            WHERE first = mt1.first AND last = mt1.last AND street = mt1.street AND state = mt1.state
            ORDER BY (age,weight)
            LIMIT 1
        )
    )
DELETE FROM mytable WHERE rowid NOT IN (SELECT cte1.rowid FROM cte1)
;
 -- Result after deletion
SELECT * FROM mytable;

Результаты

Результаты выше:

Загруженные данные

enter image description here

Запрос на выборку

enter image description here

  • Примечание: выделенные строки повторяют строки, соответствующие минимумам

Данные после удаления

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...