2012-12-07 2 views
0

SQL 서버에서 올바른 데이터를 반환하지 않는 쿼리에 문제가 있습니다. 나는 볼 수 있어야하는 간단하고 간결한 해결책이 있다는 것을 미리 양보하게되어 기쁩니다.하지만 나는 생각보다 과한 것을 생각했습니다.동일한 테이블에 다른 가격이 있음에 따라 가격이 쓸모 없게되었을 때 결정

우리는 주어진 항목에 대해 청구 된 가격과 우리가 인용 한 가격을 비교합니다. 다음 쿼리입니다.

SELECT ipl1.Id AS Id, 
     CASE s1.FirstName WHEN '' THEN s1.LastName ELSE s1.LastName + ', ' + s1.FirstName END AS SupplierName, 
     p1.Date, 
     p1.OrderNo, 
     p1.InvoiceNo, 
     i1.Number AS ItemNumber, 
     i1.Name AS ItemName, 
     ipl1.Quantity, 
     ROUND(ipl1.TaxExclusiveUnitPrice, 2) AS PriceCharged, 
     ROUND(ISNULL(p2.Amount, p4.Amount), 2) AS PriceQuoted, 
     ROUND(ROUND(ipl1.TaxExclusiveUnitPrice, 2) - ROUND(ISNULL(p2.Amount, p4.Amount), 2), 2) AS Difference, 
     ipl1.Quantity*ROUND(ROUND(ipl1.TaxExclusiveUnitPrice, 2) - ROUND(ISNULL(p2.Amount, p4.Amount), 2), 2) AS Overcharge, 
     ISNULL(p2.Starts, p4.Starts) AS QuoteDate, 
     ISNULL(p2.QuoteNo, p4.QuoteNo) AS QuoteNumber 
FROM pl_ItemPurchaseLines ipl1 
     INNER JOIN 
     pl_Purchases p1 ON p1.Id=ipl1.Purchase_Id 
     INNER JOIN 
     pl_Suppliers s1 ON s1.Id=p1.Supplier_Id 
     INNER JOIN 
     pl_Items i1 ON i1.Id=ipl1.Item_Id 
     LEFT JOIN 
     --- First Priority is the lowest Amount Current Quote or List Price 
     (
     SELECT p1.Id, 
       p1.Amount, 
       p1.Starts, 
       p1.Expires, 
       p1.QuoteNo, 
       ipl.Id AS ItemPurchaseLine_Id, 
       row_number() over (partition by ipl.Id order by p1.Amount ASC, p1.QuoteNo DESC, p1.Starts DESC) as Row 
     FROM pl_ItemPurchaseLines ipl 
       INNER JOIN 
       pl_Purchases p ON p.Id=ipl.Purchase_Id 
       INNER JOIN 
       pl_Prices p1 ON p1.Starts<=p.Date AND 
           ((p1.Expires>=p.Date AND p1.QuoteNo<>'') OR 
           (p1.Expires IS NULL AND p1.QuoteNo='')) AND 
           p1.Item_Id=ipl.Item_Id 
     ) AS p2 ON p2.Row = 1 AND 
        ipl1.Id=p2.ItemPurchaseLine_Id 
     LEFT JOIN   
     (
     SELECT p3.Id, 
       p3.Amount, 
       p3.Starts, 
       p3.Expires, 
       p3.QuoteNo, 
       ipl2.Id AS ItemPurchaseLine_Id, 
       row_number() over (partition by ipl2.Id order by p3.Expires DESC) as Row 
     FROM pl_ItemPurchaseLines ipl2 
       INNER JOIN 
       pl_Purchases p2 ON p2.Id=ipl2.Purchase_Id 
       INNER JOIN 
       pl_Prices p3 ON p3.Starts<=p2.Date AND 
           p3.QuoteNo<>'' AND 
           p3.Item_Id=ipl2.Item_Id 
     ) AS p4 ON p4.Row = 1 AND 
        ipl1.Id=p4.ItemPurchaseLine_Id 

문제의 장은 하위 쿼리에 있습니다. 가격에는 2 가지 유형이 있는데 시작일, 만료일이없고 '' '의 quoteno이며 후자의 정가로 대체 된 정가입니다. 또는 시작일, 만기일 및 견적 번호가있는 견적 가격.

문제는 첫 번째 하위 쿼리에 있습니다. 여기에서 가장 저렴한 가격의 유효한 견적이나 정가를 찾고 있는데, 대신 대체 가격을 제외하는 법을 배울 수 없습니다. 예를 들어 quoteno = ''로 가격이 만료되고 만료가 null입니다 (이들은 쉽습니다). 동일한 ID의 가격 목록을 나중에 시작 날짜와 함께 사용합니다.

나는 트리거를 기반으로 테이블에 만료 날짜를 넣는 것을 고려해 봤지만 2 개의 가격 목록이 한 번에 들어올 수있는 가능성을 다루어야하기 때문에 어려움을 겪고 있습니다. 우리는 앞으로뿐만 아니라 앞으로도 노력하고 있습니다).

가격 ID가 주어진 날짜에 대체되었지만 차선책 인 것으로 판단되면 함수를 작성할 수 있습니다.

대체로 가격이 떨어지게하려면 where 절에 뭔가를해야한다고 생각하지만 작동하지 않는 몇 가지 장황한 바로크 절을 작성했습니다. - 내가 예상대로 간단했다

USE [tempdb] 
GO 

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE TABLE [dbo].[pl_Suppliers](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [LastName] [nvarchar](100) NOT NULL, 
    [FirstName] [nvarchar](100) NOT NULL, 
    [ShortName] [nvarchar](100) NOT NULL, 
    [Prefix] [nvarchar](100) NOT NULL, 
    [UserID] [nvarchar](100) NOT NULL, 
    [Password] [nvarchar](1000) NOT NULL, 
    [SentToMyob] [bit] NOT NULL, 
CONSTRAINT [PK_Suppliers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

CREATE TABLE [dbo].[pl_ItemPurchaseLines](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Quantity] [float] NOT NULL, 
    [TaxExclusiveUnitPrice] [float] NOT NULL, 
    [TaxExclusiveTotal] [float] NOT NULL, 
    [TaxInclusiveTotal] [float] NOT NULL, 
    [TaxBasisAmount] [float] NOT NULL, 
    [TaxCode] [nvarchar](max) NOT NULL, 
    [Received] [float] NOT NULL, 
    [TaxInclusiveUnitPrice] [float] NOT NULL, 
    [Purchase_Id] [int] NOT NULL, 
    [Item_Id] [int] NOT NULL, 
CONSTRAINT [PK_pl_ItemPurchaseLines] PRIMARY KEY NONCLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

CREATE TABLE [dbo].[pl_Purchases](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [OrderNo] [nvarchar](max) NOT NULL, 
    [InvoiceNo] [nvarchar](max) NOT NULL, 
    [Date] [datetime] NOT NULL, 
    [ShipToAddressLine1] [nvarchar](max) NOT NULL, 
    [ShipToAddressLine2] [nvarchar](max) NOT NULL, 
    [ShipToAddressLine3] [nvarchar](max) NOT NULL, 
    [ShipToAddressLine4] [nvarchar](max) NOT NULL, 
    [Comment] [nvarchar](max) NOT NULL, 
    [TotalLines] [float] NOT NULL, 
    [TotalTax] [float] NOT NULL, 
    [Supplier_Id] [int] NOT NULL, 
    [SentToMyob] [bit] NOT NULL, 
    [Job_ID] [int] NULL, 
CONSTRAINT [PK_Purchases] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

CREATE TABLE [dbo].[pl_Items](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Number] [nvarchar](100) NOT NULL, 
    [Name] [nvarchar](255) NOT NULL, 
    [Supplier_Id] [int] NOT NULL, 
    [SentToMyob] [bit] NOT NULL, 
CONSTRAINT [PK_Items] PRIMARY KEY NONCLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

CREATE TABLE [dbo].[pl_Prices](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Amount] [float] NOT NULL, 
    [Starts] [datetime] NOT NULL, 
    [Expires] [datetime] NULL, 
    [QuoteNo] [nvarchar](100) NOT NULL, 
    [Item_Id] [int] NOT NULL, 
CONSTRAINT [PK_Prices] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

ALTER TABLE [dbo].[pl_Prices] WITH CHECK ADD CONSTRAINT [FK_ItemPrice] FOREIGN KEY([Item_Id]) 
REFERENCES [dbo].[pl_Items] ([Id]) 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[pl_Prices] CHECK CONSTRAINT [FK_ItemPrice] 
GO 
ALTER TABLE [dbo].[pl_Items] WITH CHECK ADD CONSTRAINT [FK_SupplierItem] FOREIGN KEY([Supplier_Id]) 
REFERENCES [dbo].[pl_Suppliers] ([Id]) 
GO 

ALTER TABLE [dbo].[pl_Items] CHECK CONSTRAINT [FK_SupplierItem] 
GO 

ALTER TABLE [dbo].[pl_Items] ADD CONSTRAINT [DF_pl_Items_SentToMyob] DEFAULT ((0)) FOR [SentToMyob] 
GO 

ALTER TABLE [dbo].[pl_Purchases] WITH CHECK ADD CONSTRAINT [FK_PurchasesSuppliers] FOREIGN KEY([Supplier_Id]) 
REFERENCES [dbo].[pl_Suppliers] ([Id]) 
GO 

ALTER TABLE [dbo].[pl_Purchases] CHECK CONSTRAINT [FK_PurchasesSuppliers] 
GO 

ALTER TABLE [dbo].[pl_Purchases] ADD CONSTRAINT [DF_pl_Purchases_SentToMyob] DEFAULT ((0)) FOR [SentToMyob] 
GO 

ALTER TABLE [dbo].[pl_ItemPurchaseLines] WITH CHECK ADD CONSTRAINT [FK_ItemPurchaseLineItem] FOREIGN KEY([Item_Id]) 
REFERENCES [dbo].[pl_Items] ([Id]) 
GO 

ALTER TABLE [dbo].[pl_ItemPurchaseLines] CHECK CONSTRAINT [FK_ItemPurchaseLineItem] 
GO 

ALTER TABLE [dbo].[pl_ItemPurchaseLines] WITH CHECK ADD CONSTRAINT [FK_Purchase_ItemPurchaseLines] FOREIGN KEY([Purchase_Id]) 
REFERENCES [dbo].[pl_Purchases] ([Id]) 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[pl_ItemPurchaseLines] CHECK CONSTRAINT [FK_Purchase_ItemPurchaseLines] 
GO 

ALTER TABLE [dbo].[pl_Suppliers] ADD CONSTRAINT [DF_pl_Suppliers_SentToMyob] DEFAULT ((0)) FOR [SentToMyob] 
GO 
+0

당신이 그것을 다른 사람들이 문제를 이해할 수 있도록 더 간단 비트 만들 수 있습니다 :이 같은

뭔가 확장 성이 가정 적절한 색인 것입니까? 여기에 귀하의 질문과 직접적인 관련이없는 것들이 많이 있다고 생각합니다. 실제로 문제를 이해하는 데 실제로 도움이 될 수도 있습니다. – BuddhiP

+0

의심의 여지가 없습니다! 내 문제는 지금이 문제가 무엇인지 해결할 수 없다는 것입니다. 문제는 첫 번째 하위 쿼리에 있습니다 .- where <= invoicedate, quoteno = ''AND 시작하는 가격을 제외하려면 where 절을 변경해야합니다. 이것은 내가 붙어있는 비트입니다) 시작 <= invoicedate, quoteno = ''및이 다른 가격의 시작> = 최초 가격이 시작되는 항목에 대한 다른 가격은 없습니다. –

+0

@ X.Jacobs는 당신의 철자법 제안에 감사하지만, 다른 철자법이 완벽하게 정당화 되었기 때문에 존재감을위한 presence와 becuase를 제외하고는. 세계에서 40 억 정도의 영어 사용자 중 북미에서 10 %의 소수 민족 (당신은 하나이고, 나는 그렇지 않습니다). 누가 'c'가 있어야하는지에 대해 철자가 틀린 사람이 있습니다. –

답변

0

내가 그것을 알아 낸 다음은 테이블 정의가

-- No there isn't I will put some up as soon as I format it -- 

: 여기

는 일부 샘플 데이터입니다.

이 뷰를 만들고 첫 번째 하위 쿼리에서이 뷰를 참조했습니다.

ALTER VIEW [dbo].[pl_PricesWithExpiry] 
AS 
SELECT [Id] 
     ,[Amount] 
     ,[Starts] 
     ,ISNULL(p.Expires, (SELECT DATEADD(DAY,-1,MIN(p1.Starts)) 
          FROM pl_Prices p1 
          WHERE p1.Item_Id=p.Item_Id AND 
          p1.Starts>p.Starts)) AS Expires 
     ,[QuoteNo] 
     ,[Item_Id] 
FROM pl_Prices p 
+0

개인적으로 "select 절 내에서 중첩 된 select 절"에서 멀리 떨어져 있습니다. "subselect"로 참조 할 것입니다. 원래의 대답으로 인해 "subselects"가 발생하지 않습니다 주 쿼리에서 반환되는 모든 단일 행에 대해 이러한 "subselects"가 실행됩니다. 이는 더 큰 데이터 세트에 대해서는 확장 할 수 없습니다. 외부 쿼리가 5k 행을 반환한다고 가정하면 "subselect"가 5k ​​번 실행됩니다. – spioter

1

솔루션은 부속의 버그가 있었다 : p1.Item_Id = p1.Item_Id 이 참조 만은 "부속"테이블 "P1"이 아닌 "외부 선택"테이블 "P"

subselect가있는 솔루션은 큰 데이터 세트의 경우 확장 할 수 없습니다.

SELECT p.[Id] 
    ,p.[Amount] 
    ,p.[Starts] 
    ,ISNULL(p.Expires, DATEADD(DAY,-1,MIN(p1.Starts)) 
    ,p.[QuoteNo] 
    ,p.[Item_Id] 
FROM pl_Prices p 

LEFT JOIN pl_Prices p1 ON 
    p1.Item_Id=p.Item_Id AND  
    p1.Starts>p.Starts 
GROUP BY 
     p.[Id] 
     ,p.[Amount] 
     ,p.[Starts] 
     ,p.[QuoteNo] 
     ,p.[Item_Id] 
+0

더 나은 및 실제 DB 테이블 refs 수정했습니다. –

관련 문제