【问题标题】:Split/explode comma delimited string with Sybase SQL Anywhere使用 Sybase SQL Anywhere 拆分/分解逗号分隔的字符串
【发布时间】:2013-10-20 11:49:06
【问题描述】:

更新: 有人将此问题标记为重复 How do I split a string so I can access item x。 但不同的是,我的问题是关于 Sybase SQL Anywhere,另一个是关于 MS SQL Server。这是两个不同的 SQL 引擎,即使它们的来源相同,它们的语法也不同。所以它不是重复的。我首先在描述和标签中写道,这都是关于 Sybase SQL Anywhere

我有字段id_list='1234,23,56,576,1231,567,122,87876,57553,1216'

我想用它来搜索IN这个字段:

SELECT * 
FROM table1
WHERE id IN (id_list)
  • idinteger

  • id_listvarchar/text

但是这种方式不起作用,所以我需要以某种方式将id_list 拆分为选择查询。

我应该在这里使用什么解决方案?我正在使用 T-SQL Sybase ASA 9 数据库 (SQL Anywhere)。

我看到的方式是使用 while 循环创建自己的函数, 并且基于分隔符位置搜索拆分的每个元素提取, 然后将元素插入到临时表中,该函数将作为结果返回。

【问题讨论】:

标签: sql tsql split sybase sqlanywhere


【解决方案1】:

您在查询中使用了文本,但这是行不通的。 使用动态查询。

【讨论】:

  • 是的,谢谢,你说得对,动态查询就是其中一种解决方案。但这不是很通用的解决方案(为每个这样的情况创建系统程序)。
【解决方案2】:

这可以在不使用动态 SQL 的情况下完成,但您需要创建几个支持对象。第一个对象是一个表值函数,它将解析您的字符串并返回一个整数表。第二个对象是一个存储过程,它有一个参数,您可以在其中传递字符串 (id_list),将其解析为表,然后最后将其加入查询。

首先,创建解析字符串的函数:

CREATE FUNCTION [dbo].[String_To_Int_Table]
(
         @list NVARCHAR(1024)
       , @delimiter NCHAR(1) = ',' --Defaults to CSV
)
RETURNS
    @tableList TABLE(
       value INT
       )
AS

BEGIN
   DECLARE @value NVARCHAR(11)
   DECLARE @position INT

   SET @list = LTRIM(RTRIM(@list))+ ','
   SET @position = CHARINDEX(@delimiter, @list, 1)

   IF REPLACE(@list, @delimiter, '') <> ''
   BEGIN
          WHILE @position > 0
          BEGIN 
                 SET @value = LTRIM(RTRIM(LEFT(@list, @position - 1)));
                 INSERT INTO @tableList (value)
                 VALUES (cast(@value as int));
                 SET @list = RIGHT(@list, LEN(@list) - @position);
                 SET @position = CHARINDEX(@delimiter, @list, 1);

          END
   END   
   RETURN
END

现在创建您的存储过程:

    CREATE PROCEDURE ParseListExample
    @id_list as nvarchar(1024)
    AS
    BEGIN

    SET NOCOUNT ON;

    --create a temp table to hold the list of ids
    CREATE TABLE #idTable (ID INT);

    -- use the table valued function to parse the ids into a table.
    INSERT INTO #idTable(ID)
    SELECT Value FROM   dbo.String_to_int_table(@id_list, ',');

    -- join the temp table of ids to the table you want to query...
    SELECT T1.* 
    FROM table1 T1
    JOIN #idTable T2
    on T1.ID = T2.ID

执行示例:

 exec ParseListExample @id_list='1234,23,56,576,1231,567,122,87876,57553,1216'

我希望这会有所帮助...

【讨论】:

  • 感谢您的回答。由于语法不同,您的解决方案在 Sybase 环境中不起作用。这可能适用于 MS SQL Server,但 Sybase 的语法略有不同。但是,我非常感谢你,因为你的部分代码(清理到 Sybase 版本)我已经替换了 Sybase sa_split_list 系统过程。
【解决方案3】:

动态查询方法如下所示:

create procedure ShowData @IdList VarChar(255)
as
  exec ('use yourDatabase; select * from MyTable where Id in ('+@IdList+')')

【讨论】:

  • 这是错误的语法,sybase 不起作用。您可以在我的另一个问题中找到如何使用动态查询创建过程的好例子:dba.stackexchange.com/a/55729/29314 Lajos Veres 也已经链接到主题“如何在 SQL Anywhere 中创建动态存储过程”。当然,谢谢你的回答。
【解决方案4】:

bsivel 的回答很好,但是为了概括它(对于逗号以外的其他分隔符),然后是行

SET @list = LTRIM(RTRIM(@list))+ ','

必须成为

SET @list = LTRIM(RTRIM(@list))+ @delimiter

第一个版本仅适用于逗号分隔的列表。

【讨论】:

    【解决方案5】:

    就像 Mikael Eriksson 所说,dba.stackexchange.com 有两个非常好的解决方案,第一个使用 sa_split_list 系统程序,第二个使用 @ 慢987654323@声明。

    对于 Sybase SQL Anywhere 9 sa_split_list 系统过程不存在,所以我做了sa_split_list 系统过程替换(我使用了 bsivel 答案的部分代码):

    CREATE PROCEDURE str_split_list
    (in str long varchar, in delim char(10) default ',')
    RESULT(
      line_num integer,
      row_value long varchar)
    BEGIN
      DECLARE str2 long varchar;
      DECLARE position integer;
    
       CREATE TABLE #str_split_list (
       line_num integer DEFAULT AUTOINCREMENT,
       row_value long varchar null,
       primary key(line_num));
    
       SET str = TRIM(str) || delim;
       SET position = CHARINDEX(delim, str);
    
       separaterows:
       WHILE position > 0 loop
           SET str2 = TRIM(LEFT(str, position - 1));
           INSERT INTO #str_split_list (row_value)
           VALUES (str2);
           SET str = RIGHT(str, LENGTH(str) - position);
           SET position = CHARINDEX(delim, str);
        end loop separaterows;
    
       select * from #str_split_list order by line_num asc;
    
    END
    

    执行方式与sa_split_list相同,默认分隔符,

    select * from str_split_list('1234,23,56,576,1231,567,122,87876,57553,1216')
    

    或带有可以更改的指定分隔符:

    select * from str_split_list('1234,23,56,576,1231,567,122,87876,57553,1216', ',')
    

    【讨论】:

      猜你喜欢
      • 2015-03-07
      • 2018-12-21
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 2017-09-09
      • 2012-05-24
      相关资源
      最近更新 更多