我正在使用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语句。这是错误。
答案 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
上有一些AND
和where
条件,则应在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>
我会:
将其集成到您的表格结构中并将表格电话列转换为in,如果没有错误,您将实现转换。
当你设置好工作时#p;然后比较执行计划,你可以选择你的赢家; - )