excel 从字符串中提取参数- SQL Server

krcsximq  于 2022-12-01  发布在  SQL Server
关注(0)|答案(4)|浏览(212)

我有一个在一列中包含字符串的表,这些字符串实际上存储了以前编写的其他SQL查询,并存储以供以后运行。它们包含“@organisationId”或“@ enterDateHere”等参数。我希望能够提取这些参数。
示例:
| 识别码|查询|
| - -|- -|
| 一个|SELECT * FROM表WHERE标识= @组织标识|
| 2个|SELECT * FROM主题WHERE创建时间〈=@开始日期AND创建时间〉= @结束日期AND标识= @输入组织此处|
| 三个|SELECT名称+ '@' +域FROM用户|
我需要以下内容:
| 识别码|参数|
| - -|- -|
| 一个|@组织ID|
| 2个|@开始日期,@结束日期,@在此处输入组织|
| 三个|空值|
不需要担心如何分开/列出它们,只要它们是清晰可见的,只要查询列出了所有它们,我不知道它们的数量。请注意,有时候查询只包含@,例如当电子邮件绑定正在进行时,但它不是一个参数。我只需要以@开头的字符串,并且在它后面至少有一个字母,以非字母字符结尾(空格、回车、逗号、分号)。如果这会导致问题,那么返回所有以@开头的字符串,我将简单地手动识别参数。
如果需要,它可以包括Excel/Python/C#的使用,但SQL是首选。

e3bfsja2

e3bfsja21#

询问参数的正式方法是使用sp_describe_undeclared_parameters,例如

exec sp_describe_undeclared_parameters @tsql =  N'SELECT * FROM topic WHERE creation_time <=@startDate AND creation_time >= @endDate AND id = @enterOrgHere'
lvmkulzt

lvmkulzt2#

通过XML和XQuery使用标记化实现非常简单。
值得注意的要点:
1.第1x 1 m0n1x正在将查询列标记为XML
1.第二个CROSS APPLY正在筛选出没有“@”符号的标记。

SQL #1

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, Query VARCHAR(2048));
INSERT INTO @tbl (Query) VALUES
('SELECT * FROM table WHERE id = @organisationId'),
('SELECT * FROM topic WHERE creation_time <=@startDate AND creation_time >= @endDate AND id = @enterOrgHere'),
('SELECT name + ''@'' + domain FROM user');
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = SPACE(1);

SELECT t.ID
    , Parameters = IIF(t2.Par LIKE '@[a-z]%', t2.Par, NULL)
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' + 
      REPLACE(Query, @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML)) AS t1(c)
CROSS APPLY (SELECT TRIM('><=' FROM c.query('data(/root/r[contains(text()[1],"@")])').value('text()[1]','VARCHAR(1024)'))) AS t2(Par)

SQL #2

添加了一个清理步骤,以首先处理常规空格以外的空格。

SELECT t.*
    , Parameters = IIF(t2.Par LIKE '@[a-z]%', t2.Par, NULL)
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<r><![CDATA[' + Query + ']]></r>' AS XML).value('(/r/text())[1] cast as xs:token?','VARCHAR(MAX)')) AS t0(pure)
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' + 
      REPLACE(Pure, @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML)) AS t1(c)
CROSS APPLY (SELECT TRIM('><=' FROM c.query('data(/root/r[contains(text()[1],"@")])')
                .value('text()[1]','VARCHAR(1024)'))) AS t2(Par);

输出

| 识别码|参数|
| - -|- -|
| 一个|@组织ID|
| 2个|@开始日期@结束日期@在此处输入组织|
| 三个|空值|

azpvetkf

azpvetkf3#

你可以使用字符串分割,然后去掉不需要的字符,下面是一个查询:

DROP TABLE IF EXISTS #TEMP

SELECT 1 AS ID ,'SELECT * FROM table WHERE id = @organisationId' AS Query
INTO #TEMP
UNION ALL SELECT 2, 'SELECT * FROM topic WHERE creation_time <=@startDate AND creation_time >= @endDate AND id = @enterOrgHere'
UNION ALL SELECT 3, 'SELECT name + ''@'' + domain FROM user'

;WITH cte as
(
    SELECT ID,
        Query,
        STRING_AGG(REPLACE(REPLACE(REPLACE(value,'<',''),'>',''),'=',''),', ') AS Parameters
    FROM #TEMP
    CROSS APPLY string_split(Query,' ')
    WHERE value LIKE '%@[a-z]%'
    GROUP BY ID,
        Query
)
SELECT #TEMP.*,cte.Parameters
FROM #TEMP
LEFT JOIN cte on #TEMP.ID = cte.ID
zynd9foi

zynd9foi4#

使用SQLServer进行解析是一个非常糟糕的主意,因为性能低,而且缺乏工具。我强烈推荐使用.net汇编或外部语言(因为你的项目是在python中),但是,作为最后的手段,你可以使用类似于这样的非常慢而且通常很糟糕的代码(这段代码只适用于SQL Server 2017+,顺便说一句。在早期版本的代码将可怕得多):

DECLARE @sql TABLE
(
  id INT PRIMARY KEY IDENTITY
, sql_query NVARCHAR(MAX)
);

INSERT INTO @sql (sql_query)
VALUES (N'SELECT * FROM table WHERE id = @organisationId')
     , (N'SELECT * FROM topic WHERE creation_time <=@startDate AND creation_time >= @endDate AND id = @enterOrgHere')
     , (N'  SELECT name + ''@'' + domain FROM user')
     ;

WITH prepared AS
(
  SELECT id
        , IIF(sql_query LIKE '%@%'
             , SUBSTRING(sql_query, CHARINDEX('@', sql_query) + 1, LEN(sql_query))
             , CHAR(32)
             ) prep_string
    FROM @sql
),
parsed AS
(
SELECT id
     , IIF(CHARINDEX(CHAR(32), value) = 0
          , SUBSTRING(value, 1, LEN(VALUE))
          , SUBSTRING(value, 1, CHARINDEX(CHAR(32), value) -1)
          ) parsed_value
  FROM prepared p
  CROSS APPLY STRING_SPLIT(p.prep_string, '@')
)
SELECT id, '@' + STRING_AGG(IIF(parsed_value LIKE '[a-zA-Z]%', parsed_value, NULL) , ', @')
  FROM parsed
GROUP BY id

相关问题