SQL 具有动态 IN 运算符和 INT 数据类型的服务器过程
SQL Server Procedure with dynamic IN operator and INT datatype
我有一个 SQL 服务器 Table 有一些基本的销售信息如下
SaleID | TotalValue | PaymentMethod | User | Date
--------|---------------|-------------------|-----------|--------------
1 | 10 | CASH | USER 1 | 2020-01-01
2 | 120 | DEBIT CARD | USER 2 | 2020-01-01
3 | 1000 | CREDIT CARD | USER 2 | 2020-01-01
4 | 305 | CREDIT CARD | USER 1 | 2020-01-01
5 | 15 | CASH | USER 5 | 2020-01-01
我需要编写一个动态过程 os 某种能够使用 SaleID 数组作为过滤器来搜索销售信息的东西。这是一个简单的select查询,如下:
SELECT
[SaleID]
,[TotalValue] as 'Total Value'
,[Date] as 'Date'
FROM
[Sales]
WHERE
[SaleID] in (1, 2, 3, 4)
我创建了以下存储过程,因此我可以输入一个 SalesID 数组:
CREATE PROCEDURE [dbo].[usp_SearchSales]
(
@SaleID NVARCHAR(max)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQL NVARCHAR(MAX)
DECLARE @ParameterDef NVARCHAR(500)
SET @ParameterDef = '@SaleID NVARCHAR(max)'
SET @SQL = 'SELECT
[SaleID]
,[TotalValue]
,[PaymentMethod]
,[User]
,[Date]
FROM
[Sales]
WHERE
-1=-1'
IF @SaleID IS NOT NULL
SET @SQL = @SQL+ ' AND SaleID in (@SaleID)'
EXEC sp_Executesql @SQL, @ParameterDef, @SaleID = @SaleID
END
GO
然后我通过Exec命令执行Procedure
EXEC [usp_SearchSales] @SaleID = '1, 2, 3, 4'
GO
然后程序returns执行时出现如下错误:
Msg 245, Level 16, State 1, Procedure usp_SearchSales, Line 26 [Batch Start Line 49]
Conversion failed when converting the nvarchar value '1, 2, 3, 4' to data type int.
这是一个 SQL 查询,用于在设计的 table
上创建和插入一些值
CREATE TABLE [Sales] (
[SaleID] int,
[TotalValue] float,
[PaymentMethod] varchar(50),
[User] varchar(50),
[Date] date
)
insert into sales values (1, 10, 'CASH', 'USER 1', '2020-01-01')
insert into sales values (2, 120, 'DEBIT CARD', 'USER 2', '2020-01-01')
insert into sales values (3, 10000, 'CREDIT CARD', 'USER 2', '2020-01-01')
insert into sales values (4, 305, 'CREDIT CARD', 'USER 1', '2020-01-01')
insert into sales values (5, 15, 'CASH', 'USER 5', '2020-01-01')
我需要一些帮助来创建一个过程,或类似的东西,其中一组 SalesID 返回我销售的销售信息。ose 销售。
像下面这样更改 SP:
我更改了查询的 SET @SQL = @SQL+ CONCAT(' AND SaleID in (',@SaleID,')') 部分。
关于注入,动态查询容易被注入,我只修复了你遇到的问题。
alter PROCEDURE [dbo].[usp_SearchSales]
(
@SaleID NVARCHAR(max)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQL NVARCHAR(MAX)
DECLARE @ParameterDef NVARCHAR(500)
SET @ParameterDef = '@SaleID NVARCHAR(max)'
SET @SQL = 'SELECT
[SaleID]
,[TotalValue]
,[PaymentMethod]
,[User]
,[Date]
FROM
[Sales]
WHERE
-1=-1'
IF @SaleID IS NOT NULL
SET @SQL = @SQL+ CONCAT(' AND SaleID in (',@SaleID,')')
print @SQL
EXEC sp_Executesql @SQL, @ParameterDef, @SaleID = @SaleID
END
GO
您可以做的另一件事是创建用户定义 Table 并在 SP 中调用它,如下所示:
CREATE TYPE [dbo].[udt_Sales] AS TABLE(
[SaleID] [int] NULL
)
SP 会是这样的:
CREATE PROCEDURE [dbo].[sp_Name]
(
@Ids [dbo].[udt_Sales] READONLY
)
AS
BEGIN
SELECT [SaleID]
,[TotalValue]
,[PaymentMethod]
,[User]
,[Date]
FROM [Sales]
WHERE [SaleID] IN (SELECT * FROM @Ids)
END
您可以像下面这样调用 SP:
DECLARE @IDs udt_Sales
INSERT INTO @IDs VALUES (1)
INSERT INTO @IDs VALUES (2)
INSERT INTO @IDs VALUES (3)
INSERT INTO @IDs VALUES (4)
EXECUTE usp_SearchSales @IDs
这比动态查询快得多。
希望对你有帮助
不幸的是SQL服务器本身不支持数组,这使得您很难(或繁琐)实现。
虽然应该可以使用字符串函数在 CSV 列表中搜索值,但让我建议一个更简洁的选项,它通过创建 table type
.
来工作
首先创建类型:
create type dbo.id_array as table (id int);
那么你的程序可以简化为一个简单的查询:
create procedure dbo.usp_searchsales
@sale_ids as dbo.id_array readonly
as
begin
set nocount on;
select
s.saleid,
s.totalvalue,
s.paymentmethod,
s.[user],
s.date
from sales s
inner join @sale_ids a on a.id = s.saleid;
end
最后,当您想要调用该过程时,您创建一个给定类型的变量,填充它,并将其作为参数传递:
declare @my_sale_ids dbo.id_array;
insert into @my_sale_ids values (1), (2), (3), (4);
execute dbo.usp_searchsales @my_sale_ids;
saleid | totalvalue | paymentmethod | user | date
-----: | ---------: | :------------ | :----- | :---------
1 | 10 | CASH | USER 1 | 2020-01-01
2 | 120 | DEBIT CARD | USER 2 | 2020-01-01
3 | 10000 | CREDIT CARD | USER 2 | 2020-01-01
4 | 305 | CREDIT CARD | USER 1 | 2020-01-01
我有一个 SQL 服务器 Table 有一些基本的销售信息如下
SaleID | TotalValue | PaymentMethod | User | Date
--------|---------------|-------------------|-----------|--------------
1 | 10 | CASH | USER 1 | 2020-01-01
2 | 120 | DEBIT CARD | USER 2 | 2020-01-01
3 | 1000 | CREDIT CARD | USER 2 | 2020-01-01
4 | 305 | CREDIT CARD | USER 1 | 2020-01-01
5 | 15 | CASH | USER 5 | 2020-01-01
我需要编写一个动态过程 os 某种能够使用 SaleID 数组作为过滤器来搜索销售信息的东西。这是一个简单的select查询,如下:
SELECT
[SaleID]
,[TotalValue] as 'Total Value'
,[Date] as 'Date'
FROM
[Sales]
WHERE
[SaleID] in (1, 2, 3, 4)
我创建了以下存储过程,因此我可以输入一个 SalesID 数组:
CREATE PROCEDURE [dbo].[usp_SearchSales]
(
@SaleID NVARCHAR(max)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQL NVARCHAR(MAX)
DECLARE @ParameterDef NVARCHAR(500)
SET @ParameterDef = '@SaleID NVARCHAR(max)'
SET @SQL = 'SELECT
[SaleID]
,[TotalValue]
,[PaymentMethod]
,[User]
,[Date]
FROM
[Sales]
WHERE
-1=-1'
IF @SaleID IS NOT NULL
SET @SQL = @SQL+ ' AND SaleID in (@SaleID)'
EXEC sp_Executesql @SQL, @ParameterDef, @SaleID = @SaleID
END
GO
然后我通过Exec命令执行Procedure
EXEC [usp_SearchSales] @SaleID = '1, 2, 3, 4'
GO
然后程序returns执行时出现如下错误:
Msg 245, Level 16, State 1, Procedure usp_SearchSales, Line 26 [Batch Start Line 49]
Conversion failed when converting the nvarchar value '1, 2, 3, 4' to data type int.
这是一个 SQL 查询,用于在设计的 table
上创建和插入一些值CREATE TABLE [Sales] (
[SaleID] int,
[TotalValue] float,
[PaymentMethod] varchar(50),
[User] varchar(50),
[Date] date
)
insert into sales values (1, 10, 'CASH', 'USER 1', '2020-01-01')
insert into sales values (2, 120, 'DEBIT CARD', 'USER 2', '2020-01-01')
insert into sales values (3, 10000, 'CREDIT CARD', 'USER 2', '2020-01-01')
insert into sales values (4, 305, 'CREDIT CARD', 'USER 1', '2020-01-01')
insert into sales values (5, 15, 'CASH', 'USER 5', '2020-01-01')
我需要一些帮助来创建一个过程,或类似的东西,其中一组 SalesID 返回我销售的销售信息。ose 销售。
像下面这样更改 SP: 我更改了查询的 SET @SQL = @SQL+ CONCAT(' AND SaleID in (',@SaleID,')') 部分。 关于注入,动态查询容易被注入,我只修复了你遇到的问题。
alter PROCEDURE [dbo].[usp_SearchSales]
(
@SaleID NVARCHAR(max)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQL NVARCHAR(MAX)
DECLARE @ParameterDef NVARCHAR(500)
SET @ParameterDef = '@SaleID NVARCHAR(max)'
SET @SQL = 'SELECT
[SaleID]
,[TotalValue]
,[PaymentMethod]
,[User]
,[Date]
FROM
[Sales]
WHERE
-1=-1'
IF @SaleID IS NOT NULL
SET @SQL = @SQL+ CONCAT(' AND SaleID in (',@SaleID,')')
print @SQL
EXEC sp_Executesql @SQL, @ParameterDef, @SaleID = @SaleID
END
GO
您可以做的另一件事是创建用户定义 Table 并在 SP 中调用它,如下所示:
CREATE TYPE [dbo].[udt_Sales] AS TABLE(
[SaleID] [int] NULL
)
SP 会是这样的:
CREATE PROCEDURE [dbo].[sp_Name]
(
@Ids [dbo].[udt_Sales] READONLY
)
AS
BEGIN
SELECT [SaleID]
,[TotalValue]
,[PaymentMethod]
,[User]
,[Date]
FROM [Sales]
WHERE [SaleID] IN (SELECT * FROM @Ids)
END
您可以像下面这样调用 SP:
DECLARE @IDs udt_Sales
INSERT INTO @IDs VALUES (1)
INSERT INTO @IDs VALUES (2)
INSERT INTO @IDs VALUES (3)
INSERT INTO @IDs VALUES (4)
EXECUTE usp_SearchSales @IDs
这比动态查询快得多。 希望对你有帮助
不幸的是SQL服务器本身不支持数组,这使得您很难(或繁琐)实现。
虽然应该可以使用字符串函数在 CSV 列表中搜索值,但让我建议一个更简洁的选项,它通过创建 table type
.
首先创建类型:
create type dbo.id_array as table (id int);
那么你的程序可以简化为一个简单的查询:
create procedure dbo.usp_searchsales
@sale_ids as dbo.id_array readonly
as
begin
set nocount on;
select
s.saleid,
s.totalvalue,
s.paymentmethod,
s.[user],
s.date
from sales s
inner join @sale_ids a on a.id = s.saleid;
end
最后,当您想要调用该过程时,您创建一个给定类型的变量,填充它,并将其作为参数传递:
declare @my_sale_ids dbo.id_array;
insert into @my_sale_ids values (1), (2), (3), (4);
execute dbo.usp_searchsales @my_sale_ids;
saleid | totalvalue | paymentmethod | user | date -----: | ---------: | :------------ | :----- | :--------- 1 | 10 | CASH | USER 1 | 2020-01-01 2 | 120 | DEBIT CARD | USER 2 | 2020-01-01 3 | 10000 | CREDIT CARD | USER 2 | 2020-01-01 4 | 305 | CREDIT CARD | USER 1 | 2020-01-01