【问题标题】:Firebird build CSV string of 1 field from multiple rows in SQLFirebird从SQL中的多行构建1个字段的CSV字符串
【发布时间】:2019-10-21 12:37:48
【问题描述】:

在 Firebird 2.5 或 3.0 和 Delphi 10.2 中:在主从配置中,每个主控始终至少有 1 个且不超过 4 或 5 个详细信息行,我需要获得具有某些字段的单行从主行和将每个详细行中的 1 个字段连接成单个 CSV 格式字符串的字段。我需要在 SQL 中完成这一切,而不必创建存储过程或用户函数,因为我需要针对客户数据库执行此操作,并且不想将对象添加到我不拥有的数据库中;如果不需要,我也不想在代码中使用计算字段,因为我们的支持人员需要能够通过数据库浏览器中的脚本来执行此操作,而不是将其构建到程序中。

为了对此进行建模,我使用了 RDB$INDICES 和 RDB$INDEX_SEGMENTS 系统表。每个索引获取一行或多行,每行都有一个段详细信息字段,非常简单:

  SELECT
    r.RDB$INDEX_NAME AS "Index",
    f.RDB$FIELD_POSITION AS "Order",
    f.RDB$FIELD_NAME AS "Fields"
  FROM RDB$INDICES r
    LEFT JOIN RDB$INDEX_SEGMENTS f ON r.RDB$INDEX_NAME = f.RDB$INDEX_NAME
  WHERE r.RDB$FOREIGN_KEY IS NULL
  AND UPPER(r.RDB$RELATION_NAME) = UPPER(:TBLNAME)
  ORDER BY r.RDB$RELATION_NAME, f.RDB$FIELD_POSITION

但我需要的是每个索引返回一行,“字段”包含一个或多个段名称 - 例如针对具有SECTIONIDKEYID 字段以及这两个字段的复合索引的表运行,上述查询中的“字段”列将包含SECTIONID,KEYID。我一生都无法弄清楚如何做到这一点,除非添加一个计算字段,该字段运行一个单独的查询并遍历构建字符串的结果集,这似乎不必要地复杂和头重脚轻。

有没有办法在 Firebird 的 SQL 中完全做到这一点?

【问题讨论】:

  • 您可以尝试LIST 聚合函数,但请务必阅读有关订单的警告。
  • 是的,就是这样!我不知道这个功能。谢谢,马克。

标签: delphi firebird


【解决方案1】:

LIST() 函数确实是要走的路,但语法可能有点棘手:

SELECT
  r.RDB$INDEX_NAME AS "Index",
  CAST((SELECT LIST(TRIM(RDB$FIELD_NAME), ',')
        FROM (SELECT RDB$FIELD_NAME
              FROM RDB$INDEX_SEGMENTS
              WHERE RDB$INDEX_NAME = r.RDB$INDEX_NAME
              ORDER BY RDB$FIELD_POSITION)) AS VARCHAR(48)) AS "Fields",
FROM RDB$INDICES r
WHERE r.RDB$FOREIGN_KEY IS NULL
  AND UPPER(r.RDB$RELATION_NAME) = UPPER(':TBLNAME')
ORDER BY r.RDB$RELATION_NAME;

CAST() 包装器只是将字段输出从文本 blob 转换为简单的 varchar,以便在 SQL 浏览器中很容易看到。 LIST() 子句中的 TRIM() 函数调用对于删除输出中多余的空格是必要的,否则您可以获得SECTIONID ,KEYID 返回。

【讨论】:

  • 我建议投射到比VARCHAR(48) 更宽的位置。在 Firebird 3 和更早版本中,对象名称可以是 31 个字符,而在 Firebird 4 中是 63 个字符。如果索引中有两列或多列,这样很容易很快用完字符。
  • 马克,在一般意义上,你是完全正确的。对于我将使用它的数据库,varchar(48) 有足够的空间。
猜你喜欢
  • 2010-11-11
  • 2013-03-26
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 2018-10-23
  • 2021-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多