我有下表和数据。
CREATE TABLE county_zip_code (
id_county INT UNSIGNED,
from_zip_code INT UNSIGNED,
to_zip_code INT UNSIGNED
);
INSERT INTO county_zip_code
(id_county, from_zip_code, to_zip_code)
VALUES
(12, 2580288, 0),
(12, 2580289, 0),
(12, 2580290, 0),
(12, 2580291, 0),
(12, 2580292, 0),
(15, 8670418, 0),
(15, 8670420, 0),
(15, 8670430, 0),
(16, 7600070, 0),
(16, 7600071, 0),
(16, 7600072, 0),
(16, 7600073, 0)
;
我想创建一个名为“county_zip_code1”的新表,其中连续的序列被其端点替换:
id_county | from_zip_code | to_zip_code 12 2580288 2580292 15 8670418 0 15 8670420 0 15 8670430 0 16 7600070 7600073
我该怎么做?
我已经阅读了SO问题“Evaluate sequential pairs of rows in SQLite”的一些答案,但这种SQL对我来说太先进了。
答案 0 :(得分:4)
在SQL中做起来有点乱。处理程序可能会更好。
从SQL和关系数据库退一步。为简单起见,请从一组数字 S 开始。假设您希望在 S 中找到所有连续的序列;你会怎么做?如果您可以排序和循环(例如在程序中),您将检查排序序列中的相邻值是否相差1.如果您仅限于设置操作,则可以通过从中获取相邻对来执行类似任务交叉产品:
C = {(n,n+1) : n ∈ S ∧ n+1 ∈ S}
要获取端点,您可以接受 C 的传递闭包。但是,SQL中的传递闭包是不优雅的;它们需要一种程序方法,而不是SQL通常提供的声明方法。
要在SQL中查找连续序列,可以对具有序列中下一个值的列执行自联接。内部联接将过滤掉单个项目,因为它们没有下一个值。 MIN
和MAX
将为您提供序列的端点,这也需要按县ID进行分组。
SELECT czc.id_county,
MIN(czc.from_zip_code) AS from_zip_code,
MAX(czc_n.from_zip_code) AS to_zip_code
FROM county_zip_code AS czc
JOIN county_zip_code AS czc_n
ON czc.id_county = czc_n.id_county
AND czc.from_zip_code = czc_n.from_zip_code-1
GROUP BY czc.id_county
请注意,此解决方案并未涵盖所有情况。如果一个县有不相交的序列,这将合并它们。将以下内容添加到示例数据中:
INSERT INTO county_zip_code
VALUES
(15, 8670424, 0),
(15, 8670425, 0),
(15, 8670426, 0),
(15, 8670450, 0),
(15, 8670451, 0),
;
,查询将导致:
+-----------+---------------+-------------+ | id_county | from_zip_code | to_zip_code | +-----------+---------------+-------------+ | 12 | 2580288 | 2580292 | | 15 | 8670424 | 8670453 | | 16 | 7600070 | 7600073 | +-----------+---------------+-------------+
获得单独的物品需要更多参与。从 S 集中,您需要没有上一个或下一个值的项目:
{(n-1, n, n+1) : n ∈ S ∧ n-1 ∉ S ∧ n+1 ∉ S}
在SQL中,再次使用自联接,但选择没有上一个或下一个值的项目。在这里,您需要部分(左或右)连接来获取这些项目(“a∉A”可以在连接表中转换为空值)。
SELECT czc.id_county,
czc.from_zip_code AS from_zip_code,
NULL AS to_zip_code
FROM county_zip_code AS czc
LEFT JOIN county_zip_code AS czc_p
ON czc.id_county = czc_p.id_county
AND czc.from_zip_code = czc_p.from_zip_code+1
LEFT JOIN county_zip_code AS czc_n
ON czc.id_county = czc_n.id_county
AND czc.from_zip_code = czc_n.from_zip_code-1
WHERE czc_p.from_zip_code IS NULL AND czc_n.from_zip_code IS NULL
将两个查询联合起来(如果需要)排序。
(
SELECT czc.id_county,
MIN(czc.from_zip_code) AS from_zip_code,
MAX(czc_n.from_zip_code) AS to_zip_code
FROM county_zip_code AS czc
JOIN county_zip_code AS czc_n
ON czc.id_county = czc_n.id_county
AND czc.from_zip_code = czc_n.from_zip_code-1
GROUP BY czc.id_county
) UNION (
SELECT czc.id_county,
czc.from_zip_code AS from_zip_code,
NULL AS to_zip_code
FROM county_zip_code AS czc
LEFT JOIN county_zip_code AS czc_p
ON czc.id_county = czc_p.id_county
AND czc.from_zip_code = czc_p.from_zip_code+1
LEFT JOIN county_zip_code AS czc_n
ON czc.id_county = czc_n.id_county
AND czc.from_zip_code = czc_n.from_zip_code-1
WHERE czc_p.from_zip_code IS NULL AND czc_n.from_zip_code IS NULL
)
ORDER BY id_county, from_zip_code
答案 1 :(得分:0)
试试这个:
CREATE TABLE county_zip_code1 AS
SELECT id_county, MIN(from_zip_code) AS from_zip_code, MAX(from_zip_code) to_zip_code
FROM county_zip_code
GROUP BY id_county