Параметризованное объединение хранимых процедур, условное для левых соединений - PullRequest
0 голосов
/ 02 декабря 2019

Я хочу сделать, я думаю, запрос UNION ALL, чтобы я мог вернуть результаты из своей таблицы заказов на основе идентификатора производителя, введенного в поле поиска. Упорядочить ссылки на> OrderItem, который затем можно связать с Product.

Я вручную набрал запрос, и он работает, но у меня возникают проблемы с его условием в моей хранимой процедуре.

Вот запрос, который я набрал вручную:

SELECT TOP 100 *
FROM [Test].[dbo].[Order] o
LEFT JOIN [Test].[dbo].[OrderItem] oi ON oi.[OrderId] = o.[Id]
LEFT JOIN  [Test].[dbo].[Product] p ON p.[Id] = oi.[ProductId]
WHERE p.[ManufacturerId] = 'mid'

Вот моя хранимая процедура:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
    @OrderId INT = 0,
    @CustomerId INT = 0,
    @ProductId INT = 0,
    @WarehouseId INT = 0,
    @BillingCountryId INT = 0,
    @PaymentMethodSystemName NVARCHAR(MAX) = NULL,
    @OrderStatusId INT = 0,
    @PaymentStatusId INT = 0,
    @ShippingStatusId INT = 0,
    @BillingEmail NVARCHAR(MAX) = NULL,
    @BillingFirstName NVARCHAR(MAX) = NULL,
    @BillingLastName NVARCHAR(MAX) = NULL,
    @ManCode NVARCHAR(MAX) = NULL,
    @Current BIT = NULL,
    @ShippingMethod NVARCHAR(MAX) = NULL,
    @CreatedFromUtc DATETIME = NULL,
    @CreatedToUtc DATETIME = NULL,
    @PageIndex INT = 0, 
    @PageSize INT = 2147483644,
    @TotalRecords INT = NULL OUTPUT
AS
BEGIN
    DECLARE @sql NVARCHAR(MAX)

    SET NOCOUNT ON;

    CREATE TABLE #TempTotal (RowNum INT IDENTITY(1,1), id INT);
    CREATE INDEX #IK_temp ON #TempTotal (RowNum);

    INSERT INTO #TempTotal ([id])
        SELECT o.[Id]
        FROM [Test].[dbo].[Order] o WITH (NOLOCK)
        LEFT JOIN [Test].[dbo].[Address] a ON a.Id = o.BillingAddressId 
                                           AND (COALESCE(@BillingEmail, '') <> ''
                                                OR COALESCE(@BillingFirstName, '') <> ''
                                                OR COALESCE(@BillingLastName, '') <> '')
        /* LEFT JOIN [Test].[dbo].[OrderItem] oi ON oi.OrderId = o.Id 
                                                 AND (COALESCE(@ManCode,'') <> '')
        LEFT join [Test].[dbo].[Product] p ON p.Id = oi.ProductId 
                                           AND (COALESCE(@ManCode, '') <> '')*/
    WHERE (@BillingEmail IS NULL OR a.[Email] = @BillingEmail)
      AND (@BillingFirstName IS NULL OR a.[FirstName] = @BillingFirstName)
      AND (@BillingLastName IS NULL OR a.[LastName] = @BillingLastName)
      -- AND (@ManCode IS NULL OR p.[ManufacturerId] = @ManCode)


    UNION ALL

    (SELECT * 
     FROM [Test].[dbo].[Product] p
     LEFT JOIN [Test].[dbo].[OrderItem] oi ON oi.[OrderId] = o.[Id]
     LEFT JOIN [Test].[dbo].[Product] p ON p.[Id] = oi.[ProductId]
     WHERE (@ManCode IS NULL OR p.[ManufacturerId] = @ManCode))

       AND -- here is error
            o.[Deleted] = 0
       AND (o.[Id] = @OrderId OR @OrderId = 0)
       AND (o.[CustomerId] = @CustomerId OR @CustomerId = 0)
       AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
       AND (@PaymentMethodSystemName IS NULL OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
       AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
       AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
       AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
       AND ((o.[OrderStatusId] != '40' AND o.[OrderStatusId] != '30' AND ((o.[ShippingStatusId] != '30' OR o.[ShippingStatusId] != '40') AND o.[Printed] = '0' AND (o.[PaymentStatusId] != '30' OR o.[PaymentStatusId] != '35' OR o.[PaymentStatusId]  != '40'))) OR @Current = 0)
       AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
       AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
    ORDER BY 
        o.[CreatedOnUtc] DESC;

    --paging
    DECLARE @PageLowerBound INT 
    SET @PageLowerBound = @PageSize * @PageIndex

    -- Return the paged records
    SELECT 
        [Id], [OrderGuid], [StoreId], [CustomerId],
        [BillingAddressId], [ShippingAddressId], 
        [OrderStatusId], [ShippingStatusId],
        [PaymentStatusId], [PaymentMethodSystemName],
        [TaxRates], [OrderTax], [OrderDiscount], [OrderTotal],
        [ShippingMethod], [CustomValuesXml], [Deleted],
        [CreatedOnUtc], [EditedStatusId],
        [WarehouseId], [PrintedOnUtc]
    FROM
        [Test].[dbo].[Order] ord
    WHERE
        ord.[Id] IN (SELECT id FROM #TempTotal tt)
    ORDER BY 
        ord.[CreatedOnUtc] DESC
        OFFSET @PageLowerBound ROWS FETCH NEXT @PageSize ROWS ONLY;

    --total records
    SELECT @TotalRecords = COUNT(*) FROM #TempTotal;

    DROP TABLE #TempTotal
END

Я не уверен, что мне нужен UNION ALL, но я чувствую, чтоэто. Я также попробовал левые соединения, которые были закомментированы, но безуспешно.

Также здесь приведен скриншот ошибки в операторе AND.

enter image description here

Кто-нибудь может мне здесь помочь?

Ответы [ 2 ]

1 голос
/ 02 декабря 2019
USE [Test]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
    @OrderId int = 0,
    @CustomerId int = 0,
    @ProductId int = 0,
    @WarehouseId int = 0,
    @BillingCountryId int = 0,
    @PaymentMethodSystemName nvarchar(max) = null,
    @OrderStatusId int = 0,
    @PaymentStatusId int = 0,
    @ShippingStatusId int = 0,
    @BillingEmail nvarchar(max) = null,
    @BillingFirstName nvarchar(max) = null,
    @BillingLastName nvarchar(max) = null,
    @ManCode nvarchar(max) = null,
    @Current bit = null,
    @ShippingMethod nvarchar(max) = null,
    @CreatedFromUtc datetime = null,
    @CreatedToUtc datetime = null,
    @PageIndex int = 0, 
    @PageSize int = 2147483644,
    @TotalRecords int = null OUTPUT
AS
BEGIN
    DECLARE
        @sql nvarchar(max)

    SET NOCOUNT ON;

    create table #TempTotal (RowNum int identity(1,1), id int);
    create index #IK_temp on #TempTotal (RowNum);

    INSERT INTO #TempTotal ([id])
        SELECT o.[Id]
        FROM [Test].[dbo].[Order] o with (NOLOCK)

    LEFT join [Test].[dbo].[Address] a on a.Id = o.BillingAddressId and (
        coalesce(@BillingEmail,'') <> ''
        or coalesce(@BillingFirstName,'') <> ''
        or coalesce(@BillingLastName,'') <> ''
    )
    /*LEFT join [Test].[dbo].[OrderItem] oi on oi.OrderId = o.Id and (
        coalesce(@ManCode,'') <> ''
    )
    LEFT join [Test].[dbo].[Product] p on p.Id = oi.ProductId and (
        coalesce(@ManCode,'') <> ''
    )*/
    WHERE (@BillingEmail IS null OR a.[Email] = @BillingEmail)
    AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
    AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)
    --AND (@ManCode IS null OR p.[ManufacturerId] = @ManCode)


    UNION ALL
    select oi.[Id] from [Test].[dbo].[Product] p

        LEFT JOIN [Test].[dbo].[OrderItem] oi ON oi.[OrderId] = o.[Id]
        LEFT JOIN  [Test].[dbo].[Product] p ON p.[Id] = oi.[ProductId]
        WHERE (@ManCode IS null OR p.[ManufacturerId] = @ManCode)

    AND -- here is error
        o.[Deleted] = 0

    AND (o.[Id] = @OrderId OR @OrderId = 0)

    AND (o.[CustomerId] = @CustomerId OR @CustomerId = 0)

    AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)

    AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)

    AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
    AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
    AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)

    AND ((o.[OrderStatusId] != '40' AND o.[OrderStatusId] != '30' AND ((o.[ShippingStatusId] != '30' OR o.[ShippingStatusId] != '40') AND o.[Printed] = '0' AND (o.[PaymentStatusId] != '30' OR o.[PaymentStatusId] != '35' OR o.[PaymentStatusId]  != '40'))) OR @Current = 0)

    AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
    AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')

    ORDER BY o.[CreatedOnUtc] DESC;

    --paging
    DECLARE @PageLowerBound int
    SET @PageLowerBound = @PageSize * @PageIndex

    -- Return the paged records
    select [Id]
      ,[OrderGuid]
      ,[StoreId]
      ,[CustomerId]
      ,[BillingAddressId]
      ,[ShippingAddressId]
      ,[OrderStatusId]
      ,[ShippingStatusId]
      ,[PaymentStatusId]
      ,[PaymentMethodSystemName]
      ,[TaxRates]
      ,[OrderTax]
      ,[OrderDiscount]
      ,[OrderTotal]
      ,[ShippingMethod]
      ,[CustomValuesXml]
      ,[Deleted]
      ,[CreatedOnUtc]
      ,[EditedStatusId]
      ,[WarehouseId]
      ,[PrintedOnUtc]
    from [Test].[dbo].[Order] ord
    where ord.[Id] in (
      select id
      from #TempTotal tt
    )
    ORDER BY ord.[CreatedOnUtc] DESC
    OFFSET @PageLowerBound ROWS FETCH NEXT @PageSize ROWS ONLY;

    --total records
    select @TotalRecords = count(*) from #TempTotal;

    DROP TABLE #TempTotal
END
0 голосов
/ 03 декабря 2019

Хорошо, так что я понял это, мне нужно было использовать оператор выбора с левым соединением, которое зависит от того, что параметр @ManCode не равен нулю.

Пейджинг также работает нормально, без необходимости добавлять дополнительныевременные таблицы:)

Вот как я это сделал:

AND (@ManCode IS null OR EXISTS (
    SELECT [OrderId], [ManufacturerId] FROM [Test].[dbo].[OrderItem] oi with (NOLOCK)
    LEFT join [Test].[dbo].[Product] p on p.ManufacturerId = oi.ManufacturerId
    WHERE oi.OrderId = o.Id AND p.[ManufacturerId] = '' + @ManCode + ''))

Итак, теперь моя полностью обновленная хранимая процедура выглядит так:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
    @OrderId INT = 0,
    @CustomerId INT = 0,
    @ProductId INT = 0,
    @WarehouseId INT = 0,
    @BillingCountryId INT = 0,
    @PaymentMethodSystemName NVARCHAR(MAX) = NULL,
    @OrderStatusId INT = 0,
    @PaymentStatusId INT = 0,
    @ShippingStatusId INT = 0,
    @BillingEmail NVARCHAR(MAX) = NULL,
    @BillingFirstName NVARCHAR(MAX) = NULL,
    @BillingLastName NVARCHAR(MAX) = NULL,
    @ManCode NVARCHAR(MAX) = NULL,
    @Current BIT = NULL,
    @ShippingMethod NVARCHAR(MAX) = NULL,
    @CreatedFromUtc DATETIME = NULL,
    @CreatedToUtc DATETIME = NULL,
    @PageIndex INT = 0, 
    @PageSize INT = 2147483644,
    @TotalRecords INT = NULL OUTPUT
AS
BEGIN
    DECLARE @sql NVARCHAR(MAX)

    SET NOCOUNT ON;

    CREATE TABLE #TempTotal (RowNum INT IDENTITY(1,1), id INT);
    CREATE INDEX #IK_temp ON #TempTotal (RowNum);

    INSERT INTO #TempTotal ([id])
        SELECT o.[Id]
        FROM [Test].[dbo].[Order] o WITH (NOLOCK)
        LEFT JOIN [Test].[dbo].[Address] a ON a.Id = o.BillingAddressId 
                                           AND (COALESCE(@BillingEmail, '') <> ''
                                                OR COALESCE(@BillingFirstName, '') <> ''
                                                OR COALESCE(@BillingLastName, '') <> '')

    WHERE (@BillingEmail IS NULL OR a.[Email] = @BillingEmail)
      AND (@BillingFirstName IS NULL OR a.[FirstName] = @BillingFirstName)
      AND (@BillingLastName IS NULL OR a.[LastName] = @BillingLastName)


    AND (@ManCode IS null OR EXISTS (
        SELECT [OrderId], [ManufacturerId] FROM [Test].[dbo].[OrderItem] oi with (NOLOCK)
        LEFT join [Test].[dbo].[Product] p on p.ManufacturerId = oi.ManufacturerId
        WHERE oi.OrderId = o.Id AND p.[ManufacturerId] = '' + @ManCode + ''))

       AND
            o.[Deleted] = 0
       AND (o.[Id] = @OrderId OR @OrderId = 0)
       AND (o.[CustomerId] = @CustomerId OR @CustomerId = 0)
       AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
       AND (@PaymentMethodSystemName IS NULL OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
       AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
       AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
       AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
       AND ((o.[OrderStatusId] != '40' AND o.[OrderStatusId] != '30' AND ((o.[ShippingStatusId] != '30' OR o.[ShippingStatusId] != '40') AND o.[Printed] = '0' AND (o.[PaymentStatusId] != '30' OR o.[PaymentStatusId] != '35' OR o.[PaymentStatusId]  != '40'))) OR @Current = 0)
       AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
       AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
    ORDER BY 
        o.[CreatedOnUtc] DESC;

    --paging
    DECLARE @PageLowerBound INT 
    SET @PageLowerBound = @PageSize * @PageIndex

    -- Return the paged records
    SELECT 
        [Id], [OrderGuid], [StoreId], [CustomerId],
        [BillingAddressId], [ShippingAddressId], 
        [OrderStatusId], [ShippingStatusId],
        [PaymentStatusId], [PaymentMethodSystemName],
        [TaxRates], [OrderTax], [OrderDiscount], [OrderTotal],
        [ShippingMethod], [CustomValuesXml], [Deleted],
        [CreatedOnUtc], [EditedStatusId],
        [WarehouseId], [PrintedOnUtc]
    FROM
        [Test].[dbo].[Order] ord
    WHERE
        ord.[Id] IN (SELECT id FROM #TempTotal tt)
    ORDER BY 
        ord.[CreatedOnUtc] DESC
        OFFSET @PageLowerBound ROWS FETCH NEXT @PageSize ROWS ONLY;

    --total records
    SELECT @TotalRecords = COUNT(*) FROM #TempTotal;

    DROP TABLE #TempTotal
END
...