【问题标题】:Contiguous sequential numbers in MySQLMySQL中的连续序列号
【发布时间】:2011-09-09 19:56:42
【问题描述】:

我有下表和数据。

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 |来自_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 对我来说太高级了。

【问题讨论】:

  • 从样本county_zip_code1 中不清楚您在寻找什么。 (为什么id_county=15 的行没有像其他行一样折叠成一行?)除了样本数据之外,您还应该始终包含对所需内容的描述。新表中的内容有哪些规则?
  • 因为我只想要顺序数据,比如 1,2,3,6,8,12,13,14,15 应该是 1-3,6,8,12-15 等等!我希望我清楚自己。提前致谢。
  • 如果这是一次性创建新表所需的操作,难道不能直接编程吗?这可能不酷,也不是最有效的方法,但另一方面,它可能比等待 SO 提出答案要快得多。只需查询order by id_country, zipcode,循环查找序列,然后将它们插入到新表中。
  • 我有 198063 条记录,我相信它会减少记录的数量。我放置了100 real records of my database 和结果here。它来自 100 条记录到 12 条记录。我现在正尝试用 PHP 来做!再次感谢。
  • @Jonadabe:顺序数据就是简单的有序数据; “1、3、5”是一个序列。更好的描述是“连续序列”(操作词是“连续”)。

标签: php mysql select phpmyadmin


【解决方案1】:

在 SQL 中做起来有点乱。用程序处理可能会更好。

暂时不要使用 SQL 和关系数据库。为简单起见,从一组数字 S 开始。假设您希望在 S 中找到所有连续的序列;你会怎么做?如果您可以排序和循环(例如在程序中),您将检查排序序列中的相邻值是否相差 1。如果您仅限于设置操作,您可以通过从交叉产品:

C = {(n,n+1) : n ∈ S ∧ n+1 ∈ S}

要获得端点,您可以采用 C 的传递闭包。然而,SQL 中的传递闭包是不优雅的;它们需要过程方法,而不是 SQL 通常提供的声明性方法。

要在 SQL 中查找连续序列,您可以对具有序列中下一个值的列执行自联接。内部连接将过滤掉孤立的项目,因为它们没有下一个值。 MINMAX 将为您提供序列的端点,这也需要按县 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 |来自_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

【讨论】:

  • outis 这太棒了!!!我正在尝试,但我认为只有第一个查询的服务器花费的时间太长,但无论如何谢谢。我认为进行这样的查询会很复杂,但仍然没有那么复杂!除了outis brain,您还使用了哪些工具来做到这一点?
  • @Jonadabe:我使用的工具是我的关系模型和关系演算的概念。基本上,了解 SQL 的基础。见"Relational database theory and SQL book recommendations?"
【解决方案2】:

试试这个:

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

【讨论】:

  • @John:这是复制粘贴的典型问题。修好了
  • 也不处理数据中的空白。这会将 1,2,4,5 折叠成 1-5,而不是 OP 想要的 1-2,4-5。
  • 谢谢马克 B。让我们希望有人知道答案并愿意分享!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-24
  • 2011-10-26
  • 2018-08-11
  • 1970-01-01
  • 2019-04-02
相关资源
最近更新 更多