访问传递查询将逗号分隔列表作为参数传递给 SQL 存储过程

Access pass-through query passing comma separated list as a parameter to SQL stored procedure

SQL 服务器是 2008。我有一个用于报告目的的 Access 2016 前端。一份报告要求从列表中选择一个或多个产品 类 进行报告。我有 VBA 使用适当的单行创建传递查询:

exec dbo.uspINVDAYS 'A3,A4,A6,AA,AB'

我有这个 SQL 代码,应该将列表作为硬编码在这里:

DECLARE @parProductClasses NVARCHAR(200) = 'A3,A4,A6,AA,AB';
DECLARE @ProductClasses NVARCHAR(200),@delimiter NVARCHAR(1) = ',';
SET @ProductClasses = @parProductClasses;

DECLARE @DAYS INT,@numDAYS int;
SET @DAYS = 395;
SET @numDAYS = @DAYS;

SELECT UPINVENTORY.StockCode, UPINVENTORY.[Description], UPINVENTORY.Supplier, UPINVENTORY.ProductClass
    , UPINVENTORY.WarehouseToUse
    , CAST(UPINVENTORY.Ebq AS INT)Ebq
    , cast(UPINVENTORY.QtyOnHand AS INT)QtyOnHand
    , cast(UPINVENTORY.PrevYearQtySold AS INT)PrevYearQtySold
    , cast(UPINVENTORY.YtdQtyIssued AS INT)YtdQtyIssued
    ,@numDAYS as numDAYS
    ,CAST(ROUND((PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS,0) AS INT)TOTAL
    ,CASE WHEN (PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS
        = 0 THEN 0
        ELSE CAST(ROUND(QTYONHAND/((PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS),0)AS INT)
    END FINAL
    ,CASE WHEN (PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS
        = 0 THEN 0
        ELSE CAST(ROUND(QTYONHAND/((PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS),0)AS INT)
    END FINAL1
FROM 
TablesCoE.dbo.vwRPUpInventory UPINVENTORY
WHERE UPINVENTORY.ProductClass  IN (Select val From TablesCoE.dbo.split(@ProductClasses,','));

当我 运行 我得到:

Msg 468, Level 16, State 9, Line 9
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_BIN" in the equal to operation.

我无法确定位置

COLLATE SQL_Latin1_General_CP1_CI_AS

该走了。我在哪里等同或比较? SQL IN 子句无法处理逗号分隔的列表,因为它不是严格的 SQL table.

这是用于创建 dbo.split() 函数的代码:

CREATE FUNCTION dbo.split(
@delimited NVARCHAR(MAX),
@delimiter NVARCHAR(100)
) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE @xml XML
SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
INSERT INTO @t(val)
SELECT  r.value('.','varchar(MAX)') as item
FROM  @xml.nodes('/t') as records(r)
RETURN
END

感谢 Sandeep Mittal,我相信其他人也有非常相似的拆分功能。 运行 此函数确实按预期运行并提供 table 逗号分隔列表对象。

DECLARE @parProductClasses NVARCHAR(200) = 'A3,A4,A6,AA,AB';
DECLARE @ProductClasses NVARCHAR(200),@delimiter NVARCHAR(1) = ',';
SET @ProductClasses = @parProductClasses;
Select val From TablesCoE.dbo.split(@ProductClasses,',')

Returns

val
A3
A4
A6
AA
AB

试试这个。

WHERE concat(',',@ProductClasses,',') like concat('%',UPINVENTORY.ProductClass,'%')

这是一种检查 productClass 是否在 @productClasses 列表中的愚蠢方法。

在尝试使用预制的 table 值变量与 WHERE 子句中的动态变量之后,两者都不起作用,然后我开始尝试 COLLATE 语句的不同位置。我很自满地将 COLLATE 应用到右侧,并在 SQL 错误消息的左侧列出了排序规则。我尝试了 WHERE 子句左侧 SQL 错误消息右侧列出的排序规则,现在 SQL 代码符合规范。这是:

DECLARE @parProductClasses NVARCHAR(200) = 'A3,A4,A6,AA,AB';
DECLARE @ProductClasses NVARCHAR(200),@delimiter NVARCHAR(1) = ',';
SET @ProductClasses = @parProductClasses;

DECLARE @DAYS INT,@numDAYS int;
SET @DAYS = 395;
SET @numDAYS = @DAYS;

SELECT UPINVENTORY.StockCode, UPINVENTORY.[Description], UPINVENTORY.Supplier, UPINVENTORY.ProductClass
    , UPINVENTORY.WarehouseToUse
    , CAST(UPINVENTORY.Ebq AS INT)Ebq
    , cast(UPINVENTORY.QtyOnHand AS INT)QtyOnHand
    , cast(UPINVENTORY.PrevYearQtySold AS INT)PrevYearQtySold
    , cast(UPINVENTORY.YtdQtyIssued AS INT)YtdQtyIssued
    ,@numDAYS as numDAYS
    ,CAST(ROUND((PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS,0) AS INT)TOTAL
    ,CASE WHEN (PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS
        = 0 THEN 0
        ELSE CAST(ROUND(QTYONHAND/((PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS),0)AS INT)
    END FINAL
    ,CASE WHEN (PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS
        = 0 THEN 0
        ELSE CAST(ROUND(QTYONHAND/((PREVYEARQTYSOLD + YTDQTYISSUED)/@DAYS),0)AS INT)
    END FINAL1
FROM 
TablesCoE.dbo.vwRPUpInventory UPINVENTORY
WHERE UPINVENTORY.ProductClass COLLATE Latin1_General_BIN IN (SELECT val FROM TablesCoE.dbo.split(@ProductClasses,','));

感谢@Krish 和@Isaac 的建议。 蒂姆