Доступ к сквозному запросу, передаваемому через запятую, в качестве параметра к хранимой процедуре SQL - PullRequest
0 голосов
/ 10 марта 2020

Сервер 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

должен go. Где я приравниваю или сравниваю? Предложение SQL IN не может обрабатывать список, разделенный запятыми, поскольку он не является строгой таблицей SQL.

Вот код, использованный для создания функции 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

Благодаря Сандипу Митталу и, я уверен, другие имеют очень похожие функции разделения. При отдельном запуске эта функция работает должным образом и предоставляет таблицу объектов списка, разделенных запятыми.

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,',')

Возвращает

val
A3
A4
A6
AA
AB

Ответы [ 2 ]

0 голосов
/ 11 марта 2020

После попытки использовать готовую табличную переменную по сравнению с «на лету» в предложении WHERE ни одна из них не сработала, затем я начал пробовать различные размещения оператора COLLATE. Я был удовлетворен применением COLLATE справа с параметрами сортировки, указанными слева в сообщении об ошибке SQL. Я пробовал сопоставление, приведенное в правой части сообщения об ошибке SQL слева от предложения WHERE, и код SQL теперь работает точно c. Вот оно:

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,','));

Спасибо за ваши предложения @ Kri sh и @ Исаа c. Тим

0 голосов
/ 11 марта 2020

попробуйте это.

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

это глупый способ проверить, находится ли ваш productClass в списке @productClasses.

...