需要帮助来创建动态SQL查询

时间:2018-04-20 13:40:17

标签: sql sql-server tsql stored-procedures

我正在使用SQL Server数据库。我有一个SQL查询,我必须使用SQL字符串在存储过程中编写,我无法编写它。

SQL查询

SELECT TOP (1000) 
    [OfficeNo], [CustNo], [SAPNo],
    [Name1], [Name2],
    [HomePhone], [OtherPhone], [FaxPhone], [cellPhone], [workPhone]
FROM 
    [dbo].[tblCustomers]
WHERE 
    OfficeNo = '1043' 
    AND (REPLACE(REPLACE(REPLACE(REPLACE(HomePhone,'(',''),' ',''),'-',''),')','') = '6147163987' )
         OR (REPLACE(REPLACE(REPLACE(REPLACE(OtherPhone,'(',''),' ',''),'-',''),')','') = '6147163987'
         OR (REPLACE(REPLACE(REPLACE(REPLACE(FaxPhone,'(',''),' ',''),'-',''),')','') = '6147163987'
         OR (REPLACE(REPLACE(REPLACE(REPLACE(cellPhone,'(',''),' ',''),'-',''),')','') = '6147163987'
         OR (REPLACE(REPLACE(REPLACE(REPLACE(workPhone,'(',''),' ',''),'-',''),')','') = '6147163987'))))

上面的SQL查询有效,但是由于大量的单引号和冒号,我无法在动态SQL字符串中转换上述REPLACE语句。这是错误。

4 个答案:

答案 0 :(得分:1)

这是另一种选择。这是使用内联表值函数,它比标量函数更好的性能。有几种方法可以使用,但除了所需的清洁值之外,我还选择传入存储的(或格式化的)值。这允许我们使用交叉应用来过滤掉那些不匹配的行。

create function PhoneNumberCheck
(
    @StoredValue varchar(20)
    , @CleanValue varchar(20)
) returns table as return

select CleanValue = @CleanValue
where @CleanValue = REPLACE(REPLACE(REPLACE(REPLACE(@StoredValue, '(', ''),' ', ''), '-', ''), ')', '')

然后,要使用此功能,我们只需要为每列电话号码值调用它。我应该提到的一件事是在您的原始查询中,您有前1000名,但您没有订单。这意味着您无法确保返回哪些行。如果你使用top,你几乎总是需要包括一个订单。

SELECT TOP (1000) [OfficeNo]
    ,[CustNo]
    ,[SAPNo]
    ,[Name1]
    ,[Name2]
    ,[HomePhone]
    ,[OtherPhone]
    ,[FaxPhone]
    ,[cellPhone]
    ,[workPhone]
FROM [dbo].[tblCustomers] c
cross apply dbo.PhoneNumberCheck(HomePhone, '6147163987') hp
cross apply dbo.PhoneNumberCheck(OtherPhone, '6147163987') op
cross apply dbo.PhoneNumberCheck(FaxPhone, '6147163987') fp
cross apply dbo.PhoneNumberCheck(cellPhone, '6147163987') cp
cross apply dbo.PhoneNumberCheck(workPhone, '6147163987') wp
where OfficeNo = '1043'
--order by ??? 

答案 1 :(得分:0)

根据您使用的SQL服务器版本,现在有更好的方法可以执行此操作,但这是我必须为2012年及更早版本清理手机的功能。

Create FUNCTION [dbo].[fn_CleanPhone] (
   @phone VARCHAR(20))
RETURNS VARCHAR(10)
AS

BEGIN
   RETURN CASE WHEN ISNUMERIC(LEFT(NULLIF(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@phone,
                    '`', 1), '{', ''), '}', ''),'_', ''), ' ', ''), '-', ''), '.', ''), '(', ''), ')', ''), '/', ''), ''), 10)) = 1
               THEN LEFT(NULLIF(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@phone,
                    '`', 1), '{', ''), '}', ''), '_', ''), ' ', ''), '-', ''), '.', ''), '(', ''), ')', ''), '/', ''), ''), 10)
               ELSE NULL
         END
END

然后调用这样的函数代替所有的NULL和IF语句以及LEFT语句,因为所有这些都是在上面的函数中完成的

SELECT dbo.fn_CleanPhone('1234-22(23)')

所以这在你的where语句中:

where OfficeNo = '1043' 
AND (
    dbo.fn_CleanPhone(HomePhone) = '6147163987' )
    OR dbo.fn_CleanPhone(OtherPhone) = '6147163987' )
    OR dbo.fn_CleanPhone(FaxPhone) = '6147163987' )
    OR dbo.fn_CleanPhone(cellPhone) = '6147163987' )
    OR dbo.fn_CleanPhone(workPhone) = '6147163987' )
) -- end for and

答案 2 :(得分:0)

创建一个函数来返回输入的数字(抱歉命名错误):

CREATE FUNCTION GETCleand(@INPUT VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS 
BEGIN
DECLARE @INDEX INT = 0
DECLARE @CLEANED VARCHAR(MAX)=''
WHILE(@INDEX<LEN(@INPUT))
BEGIN
    IF(ISNUMERIC(SUBSTRING(@INPUT,@INDEX,1))=1)
            SET @CLEANED = @CLEANED + SUBSTRING(@INPUT,@INDEX,1)
        SET @INDEX = @INDEX + 1
END
RETURN @CLEANED
END


SELECT TOP (1000) [OfficeNo]
      ,[CustNo]
      ,[SAPNo]
      ,[Name1]
      ,[Name2]
      ,[HomePhone]
      ,[OtherPhone]
      ,[FaxPhone]
      ,[cellPhone]
      ,[workPhone]
  FROM [dbo].[tblCustomers]
  where OfficeNo = '1043' and 
(GetCleaned(HomePhone) = '6147163987' 
  or GetCleaned(OtherPhone) = '6147163987'
  or GetCleand(FaxPhone) = '6147163987'
  or GetCleand(cellPhone) = '6147163987'
  or GetCleand(workPhone) = '6147163987')

如果OR上有一些ANDwhere条件,则应在OR个上使用括号

答案 3 :(得分:0)

使用逐行查询时,最简单的方法是让TSQL在没有性能损失的情况下执行循环。

我已经创建了一个小测试查询,希望在您的情况下更容易实现它。

<IndirectSalesMessage>
   <Header>
      <TargetApplication>EnterpriseOne 9.1</TargetApplication>
      <InterfaceName>CA_Tracing</InterfaceName>
      <OriginatingApplication>Alliance-Model N</OriginatingApplication>
   </Header>
   <DIST>
      <distributor_e1number>7320177</distributor_e1number>
      <debit_memo_number>June20177320177</debit_memo_number>
   </DIST>
</IndirectSalesMessage>

我会:

  1. 将测试表中输入的值替换为测试用例
  2. 运行查询并根据需要更改正则表达式
  3. 将其集成到您的表格结构中并将表格电话列转换为in,如果没有错误,您将实现转换。

    当你设置好工作时#p;然后比较执行计划,你可以选择你的赢家; - )