在SQLITE中选择每个组的最小行吗?

时间:2018-12-05 00:42:04

标签: sqlite

假设我已经创建了一个SQLITE表,其中包含四个TEXT值first, last, street, state和两个INTEGER值age, weight。我想创建一个查询,该查询将选择first, last, street, state最低的age的行,如果两个条目的所有weight的值都相同,则使用first, last, street, state, age作为决胜分

我想我可以做类似的事情:

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(第一,最后,街道,州)约束,并通过增大年龄和增大权重来添加行。这将产生等效的结果。)

1 个答案:

答案 0 :(得分:0)

我相信以下可能合适:-

-- 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以下,否则需要更大的数字))
  • are子句将此值与相同的开头,结尾,街道和州(例如,由于选定的行均根据组而定)不需要的GROUP BY来比较此值的最小值。

使用(通过将WITH子句中的查询包装为公用表表达式(CTE),然后使用CTE(cte1)来驱动DELETES来删除SELECT中没有的行,这是一件简单的事情。删除不在提取的列表中的行):-

-- 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)
;
  • 注意假定该表不是WITHOUT 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)
;
  • 请注意,对于重复的最低年龄和体重行,是否应该采取任何具体措施尚不清楚(请参见上面突出显示的插入内容)
    • 按原样,此类重复项将保留(如果将合并的列设为复合UNIQUE约束则将不存在)

-- 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