2012-12-27 23 views
0

有人能帮我吗?我正在尝试编写一个SQL查询并在2-3天内遇到问题。让我先定义问题。一对多sql查询性能不错

我有2个表

  1. Payment_Schedule_Master
 [PAYMENT_SCHEDULE_MASTER_ID] [int] NOT NULL, Primary key 
    [FPI_ID] [varchar](9) NOT NULL, 
    [DELETE_FLAG] [char](1) NOT NULL, 
    [CREATED_BY] [varchar](30) NOT NULL, 
    [CREATED_DATE] [datetime] NOT NULL, 
    [MODIFY_BY] [varchar](30) NOT NULL, 
    [MODIFY_DATE] [datetime] NOT NULL
  1. Payment_Schedule_Detail
 [PAYMENT_SCHEDULE_DETAIL_ID] [int] IDENTITY(1,1) NOT NULL, Primary key 
    [PAYMENT_SCHEDULE_MASTER_ID] [int] NOT NULL, Foreign key to master table 
    [PAY_YEAR] [int] NOT NULL, 
    [PAY_MONTH] [int] NOT NULL, 
    [ACTUAL] [money] NULL, 
    [FORECAST] [money] NULL, 
    [DELETE_FLAG] [char](1) NOT NULL, 
    [CREATED_BY] [varchar](30) NOT NULL, 
    [CREATED_DATE] [datetime] NOT NULL, 
    [MODIFY_BY] [varchar](30) NOT NULL, 
    [MODIFY_DATE] [datetime] NOT NULL

有一个一对多relati两者之间的关系:Master有一个条目并且detail有很多。 Payment_Schedule_Detail有一个id,外键,实际,预测和很多列。实际和预测将包含数值。

问题:
我想那些Payment_Schedule_Master行具有ActualForeCast等于0

我的查询:

我尝试这个查询

Select 
    t.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 
    t.ActualSum, t.ForecastSum 
from 
    (Select 
     SUM(Actual) As ActualSum, 
     SUM (forecast) AS ForecastSum, 
     PAYMENT_SCHEDULE_MASTER_ID 
    from 
     [dbo].[PAYMENT_SCHEDULE_DETAIL] 
    group by 
     PAYMENT_SCHEDULE_MASTER_ID) t 
Inner Join 
    dbo.PAYMENT_SCHEDULE_MASTER psm on psm.PAYMENT_SCHEDULE_MASTER_ID = t.PAYMENT_SCHEDULE_MASTER_ID 
where 
    t.ActualSum = t.ForecastSum 
and t.ActualSum = 0 

这个查询的问题是,如果Actual有200在一月和二月-200在十二月它会选择该标题,因为SUM (Actual)将是0这是错误的。

我不知道如何修改查询,它应该只得到其中有实际的0这些头衔和预测0

测试:
也会不会有人让我知道如何测试方法?

更新:尝试了此查询,但它需要8秒。

Select 
    t.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 
    t.ActualSum, t.ForecastSum, psd.ACTUAL, psd.FORECAST 
from 
    (Select 
     SUM(Actual) As ActualSum, SUM (forecast) AS ForecastSum, 
     PAYMENT_SCHEDULE_MASTER_ID 
    from 
      [dbo].[PAYMENT_SCHEDULE_DETAIL] 
    group by 
      PAYMENT_SCHEDULE_MASTER_ID) t 
Inner Join 
    dbo.PAYMENT_SCHEDULE_MASTER psm on psm.PAYMENT_SCHEDULE_MASTER_ID = t.PAYMENT_SCHEDULE_MASTER_ID 
Inner Join 
    [dbo].[PAYMENT_SCHEDULE_DETAIL] psd on psm.PAYMENT_SCHEDULE_MASTER_ID = psd.PAYMENT_SCHEDULE_MASTER_ID 
where 
    t.ActualSum = t.ForecastSum 
    and t.ActualSum = 0 
    and psd.ACTUAL = 0 
order by 
    psm.FPI_ID 

数据和输出:

psm_id Actual  ForeCast [other columns] 
900  10000.00 0.00 
900  -10000.00 0.00 
900  0.00  0.00 
912  0.00  0.00 
912  0.00  0.00 
912  0.00  0.00 

psm_id = Payment_Schedule_Master_ID

Payment_Schedule_Master_Id 900的实际总和为0,它不应该出现的结果。但912将出现在结果中,因为所有记录都是0.我希望这有助于。

+0

你能定义“好”的表现吗?什么是你的查询的解释计划和你的表格的结构? – Ben

+0

好的表现是在1秒内。 –

+0

我用模式更新了这个问题。 –

回答

0

谢谢你的答案,但它根本不工作。

在我的数据库中有一个我没有看到的特例。这就是说,如果实际和预测值对于特定的Payment_Schedule_Id都是0,它将只有一行。

Select PAYMENT_SCHEDULE_MASTER_ID from (
Select COUNT(*) As IdCount, PAYMENT_SCHEDULE_MASTER_ID, ACTUAL , FORECAST 
from PAYMENT_SCHEDULE_DETAIL 
group by PAYMENT_SCHEDULE_MASTER_ID, ACTUAL, FORECAST) t 
where t.IdCount = 1 
and t.ACTUAL = 0.00 
and t.FORECAST = 0.00 

上面是解决方案。

0

要测试你可以使用类似SQL小提琴的东西。

尝试this

我尝试以下SQL

select * 
from Payment_Schedule_Master mast 
where ((select sum(actual) from Payment_Schedule_Detail where main = mast.id) = 0) 
and ((select sum(forecast) from Payment_Schedule_Detail where main = mast.id) = 0) 

它更简单,我认为它使你想要什么

+0

你的查询使用sum函数,如果在jan中的数量是200,在dec中是-200,那么它将为0,并且会带来错误的标题。我用模式更新了这个问题。 –

0
Select 
    t.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 
    t.ActualSum, t.ForecastSum, psd.ACTUAL, psd.FORECAST 
from 
    (Select t1.ActualSum,t1.ForecastSum,t1.PAYMENT_SCHEDULE_MASTER_ID 
    from 
    (Select 
     SUM(Actual) As ActualSum, SUM (forecast) AS ForecastSum, PAYMENT_SCHEDULE_MASTER_ID 
    from 
      [CILS].[dbo].[PAYMENT_SCHEDULE_DETAIL] 
    group by 
      PAYMENT_SCHEDULE_MASTER_ID) t1 
      where 
    t1.ActualSum = 0 and t1.ForecastSum=0)t  

Inner Join 
    [Cils].dbo.PAYMENT_SCHEDULE_MASTER psm on psm.PAYMENT_SCHEDULE_MASTER_ID = t.PAYMENT_SCHEDULE_MASTER_ID 
Inner Join 
    [CILS].[dbo].[PAYMENT_SCHEDULE_DETAIL] psd on psm.PAYMENT_SCHEDULE_MASTER_ID = psd.PAYMENT_SCHEDULE_MASTER_ID 
order by 
    psm.FPI_ID 
+0

我试过你的查询,它给出了相同的结果。有很多记录其中实际有一些值,而不是0 –

0

你原来的查询是非常接近你需要什么。您正在查找实际和预测始终为零的情况。好吧,如果他们总是0,则该绝对值之和为0,所以试试这个:

Select 
    t.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 
    t.ActualAbsSum, t.ForecastAbsSum 
from 
    (Select 
     SUM(abs(Actual)) As ActualAbsSum, 
     SUM(abs(forecast)) AS ForecastAbsSum, 
     PAYMENT_SCHEDULE_MASTER_ID 
    from 
     [dbo].[PAYMENT_SCHEDULE_DETAIL] 
    group by 
     PAYMENT_SCHEDULE_MASTER_ID) t 
Inner Join 
    dbo.PAYMENT_SCHEDULE_MASTER psm on psm.PAYMENT_SCHEDULE_MASTER_ID = t.PAYMENT_SCHEDULE_MASTER_ID 
where 
    t.ForecastAbsSum = 0 and t.ActualAbsSum = 0 

你试图让他们在哪里0任何例子,如:

Select psm.* 
from dbo.PAYMENT_SCHEDULE_MASTER psm 
where psm.PAYMENT_SCHEDULE_MASTER_ID in (select PAYMENT_SCHEDULE_MASTER_ID 
             from [PAYMENT_SCHEDULE_DETAIL] 
             where actual = 0 and forecast = 0 
             ) 

这只是为了清楚起见而使用in而不是join(两者在SQL Server引擎中大致相同)。

+0

谢谢戈登,但你的查询仍然不能补救实际和预测的总和值的解决方案,让我更新与示例输出的问题。 –

3

什么 -

select * from Payment_Schedule_Master 
where NOT EXISTS 
(
    SELECT null FROM Payment_Schedule_Detail 
     where (forecast != 0 or actual != 0) and 
     Payment_Schedule_Master.id = PAYMENT_SCHEDULE_MASTER_ID 
) 

注意,这也将找到Payment_Schedule_Master不具有任何相关payment_schedule_details线。

+0

花了我五分钟的时间来试着理解这里所需的东西,但我相信这是正确的答案,而且这很简单。他希望所有的细节都有0个实际和0个预测的所有主记录。为了避免没有详细信息的记录,他可以简单地将连接添加到存在外的详细信息表中。这会限制结果,并且假设索引设置正确,应该不会影响性能。 –

0

在我看来像你需要和你之前,你的“实际”和“预测”列,其中使用:

Select 
    t.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 
    t.ActualSum, t.ForecastSum 
from 
    (Select 
     SUM(Actual) As ActualSum, 
     SUM (forecast) AS ForecastSum, 
     PAYMENT_SCHEDULE_MASTER_ID 
    from 
     [dbo].[PAYMENT_SCHEDULE_DETAIL] 
    where Actual=0 and forecast=0 
    group by 
     PAYMENT_SCHEDULE_MASTER_ID) t 
Inner Join 
    dbo.PAYMENT_SCHEDULE_MASTER psm on psm.PAYMENT_SCHEDULE_MASTER_ID = t.PAYMENT_SCHEDULE_MASTER_ID 

说了,如果性能是一个问题,你并不需要总结实际和预测,因为你正在求和零。然后,我们可以做的更简单:

Select 
    t.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 0 as ActualSum, 0 as ForecastSum 
from 
    (Select distinct 
     PAYMENT_SCHEDULE_MASTER_ID 
    from 
     dbo.PAYMENT_SCHEDULE_DETAIL 
    where Actual=0 and forecast=0) t 
Inner Join 
    dbo.PAYMENT_SCHEDULE_MASTER psm 
On psm.PAYMENT_SCHEDULE_MASTER_ID = t.PAYMENT_SCHEDULE_MASTER_ID 

我不是在性能优化太聪明了 - 如果你的查询生成很多行,在加入之前采摘不同的,如上所述,可能会更快。但你可以试试这个:

Select distinct 
    psd.PAYMENT_SCHEDULE_MASTER_ID, psm.FPI_ID, 0 as ActualSum, 0 as ForecastSum 
from 
    dbo.PAYMENT_SCHEDULE_DETAIL psd 
Inner Join 
    dbo.PAYMENT_SCHEDULE_MASTER psm 
On 
    psm.PAYMENT_SCHEDULE_MASTER_ID = psd.PAYMENT_SCHEDULE_MASTER_ID 
Where 
    Actual=0 and forecast=0 

这是比较简单的,但它可能会慢,因为它在过滤不同的行之前加入行。而且,别忘了索引你的FK,除非你正在做大量的数据写入。

0

我相信这是你在找什么:

SELECT M.* 
FROM Payment_Schedule_Detail D 
JOIN Payment_Schedule_Master M 
ON M.PAYMENT_SCHEDULE_MASTER_ID = D.PAYMENT_SCHEDULE_MASTER_ID 
GROUP BY D.PAYMENT_SCHEDULE_MASTER_ID 
HAVING SUM(D.Actual) = 0 AND SUM(D.Forecast) = 0 

或本:

SELECT M.* 
FROM (SELECT PAYMENT_SCHEDULE_MASTER_ID, 
      SUM(Actual) ActualSum, SUM(Forecast) ForecastSum 
     FROM Payment_Schedule_Detail 
     GROUP BY PAYMENT_SCHEDULE_MASTER_ID) D 
JOIN Payment_Schedule_Master M 
ON M.PAYMENT_SCHEDULE_MASTER_ID = D.PAYMENT_SCHEDULE_MASTER_ID 
WHERE ActualSum = 0 AND ForecastSum = 0 

不知道哪一个是更好的性能方面。我认为第二个会创建一个临时表,因此速度较慢,但​​它可能取决于优化器。

根据您正在使用的SQL数据库的类型,外键可能会自动获取索引,也可能不会自动获取索引,如果没有,您应该索引您的外键。

0
SELECT psm_id, ActualSum, ForecastSum FROM 
(SELECT 
    PAYMENT_SCHEDULE_MASTER_ID AS psm_id, SUM(psd.Actual) As ActualSum, SUM (psd.forecast) AS ForecastSum 
FROM 
    [dbo].[PAYMENT_SCHEDULE_DETAIL] psd, dbo.PAYMENT_SCHEDULE_MASTER psm 
GROUP BY PAYMENT_SCHEDULE_MASTER_ID 
) ts, dbo.PAYMENT_SCHEDULE_MASTER psm1 
WHERE psm1.PAYMENT_SCHEDULE_MASTER_ID = ts.psm_id 
AND ts.ActualSum = 0 AND ts.ForecastSum 
ORDER BY 
    psm1.FPI_ID