3

我正在使用 SQL Server 管理器 2008。

我有一个查询如下:

SELECT dbo.iLines.Part,
   dbo.iLines.Pg,
   SUM(dbo.iLines.Qty) as sales6months,
   dbo.iLines.Prefix       
FROM 
   Autopart.dbo.iLines
RIGHT JOIN
   dbo.product  
ON
   dbo.product.keycode = dbo.ilines.part                 

where  prefix = 'i'
   and ([datetime] > dateadd(month, -6, getdate()))
   and dbo.ilines.part = 'BK939'

group by 
   dbo.ilines.pg,
   dbo.ilines.part,
   dbo.ilines.prefix

order by sales6months desc

所以解释一下,我想获得产品表中所有产品的最近 6 个月的销售额。

问题是某些产品不会有任何销售。我仍然需要他们展示。所以我要求的是显示所有产品最近 6 个月的销售额,包括 0 销售额。

“iLines”是导致问题的表,因为零件号仅在有销售时才存在。

我知道可能有一种方法可以进行多个查询等。但我只需要在 1 个查询中完成所有操作。

我尝试让 null 通过,但什么也没做,而且使用 null 真的很可怕,呵呵。

添加到此查询的任何代码片段都会非常棒!

非常感谢!

另外,如果您需要更多信息,请询问!

更新!是的,抱歉 Datetime 仅存在于 Ilines 中。

Ilines = 销售表 Product = 只是我们所有产品的表格

这是主要查询,它的意思是拉出过去 6 个月内销量最高的“n”个零件。除了我说它不显示未售出的零件外,它可以正常工作。

ALTER PROCEDURE [dbo].[MyPareto]
@pgParam varchar(255)
AS
SELECT
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.part,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto

FROM
OPENQUERY(SACBAUTO, 'SELECT dbo.iLines.Part,
                            dbo.iLines.Pg,
                            SUM(dbo.iLines.Qty) as   sales6months,
                            dbo.iLines.Prefix 
                     FROM Autopart.dbo.iLines 
                     where prefix = ''i''
                     and [datetime] > dateadd(month, -6,    getdate())
                     group by 
                     dbo.ilines.pg,
                     dbo.ilines.part,
                     dbo.ilines.prefix
                     order by sales6months desc') i
RIGHT JOIN
dbo.OldParetoAnalysis
on
i.part collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part
INNER JOIN
dbo.NewParetoAnalysis
ON
dbo.OldParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS =     dbo.NewParetoAnalysis.Part
LEFT JOIN
OPENQUERY(SACBAUTO, 'SELECT dbo.aLines.Part,
                            dbo.aLines.Pg,
                            SUM(dbo.aLines.Qty) as LostSales6Months,
                            dbo.aLines.Prefix 
                     FROM Autopart.dbo.aLines 
                     where prefix = ''d''
                     and [datetime] > dateadd(month, -6, getdate())
                     group by 
                     dbo.alines.pg,
                     dbo.alines.part,
                     dbo.alines.prefix
                     order by LostSales6Months desc') a
ON
dbo.NewParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS = a.part
WHERE
    i.pg = @pgParam
GROUP BY
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.part,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto
ORDER BY
dbo.OldParetoAnalysis.Pareto asc

将帕累托视为最佳部分的联盟。希望这会有所帮助,我尽量避免添加它,因为它可能会让一些人不发表评论。

好的新更新,这个开放查询有效!!!

SELECT                      
                        dbo.product.Keycode,
                        dbo.iLines.Pg,
                        SUM(COALESCE(dbo.iLines.Qty, 0)) as sales6months,
                        dbo.iLines.Prefix 
                     FROM 
                        Autopart.dbo.product
                     LEFT OUTER JOIN
                        Autopart.dbo.ilines
                     ON
                        dbo.product.keycode = dbo.ilines.part
                        AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )
                     WHERE
                        (dbo.iLines.Prefix = 'i' OR dbo.iLines.Prefix is null)
                        AND dbo.product.keycode = 'BK939'
                     group by 
                        dbo.ilines.pg,
                        dbo.product.keycode,
                        dbo.ilines.prefix
                     order by sales6months desc#

但是当我加入我的帕累托表时,如下所示:

SELECT
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.keycode,
   i.sales6months


FROM
OPENQUERY(SACBAUTO, 'SELECT                     
                        dbo.product.Keycode,
                        dbo.iLines.Pg,
                        SUM(COALESCE(dbo.iLines.Qty, 0)) as sales6months,
                        dbo.iLines.Prefix 
                     FROM 
                        Autopart.dbo.product
                     LEFT OUTER JOIN
                        Autopart.dbo.ilines
                     ON
                        dbo.product.keycode = dbo.ilines.part
                        AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )/* must be this*/
                     WHERE
                        (dbo.iLines.Prefix = ''i'' OR dbo.iLines.Prefix is null)
                     group by 
                        dbo.ilines.pg,
                        dbo.product.keycode,
                        dbo.ilines.prefix
                     order by sales6months desc') i
LEFT JOIN
dbo.OldParetoAnalysis
on
i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part
WHERE i.pg = '40' AND i.keycode = 'BK939'

结果返回相同,所以这意味着问题是当我去加入时,但旧的帕累托确实包含零件号,我也尝试过更改加入....我希望这缩小了对问题的搜索范围我希望有人知道为什么会这样!

最终更新!哇,这很长,但最后我发现了问题,我不得不使用产品表 PG 字段重新检查!!!!!!因为它不会为空!!这是代码!

ALTER PROCEDURE [dbo].[MyPareto32TEST]
@pgParam varchar(255)

AS
SELECT
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.keycode,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto

FROM
OPENQUERY(SACBAUTO, 'SELECT                      
                    dbo.product.Keycode,
                    dbo.iLines.Pg,
                    dbo.product.pg as ppg,
                    SUM(COALESCE(dbo.iLines.Qty, 0)) as sales6months,
                    dbo.iLines.Prefix 
                 FROM 
                    Autopart.dbo.product
                 LEFT OUTER JOIN
                    Autopart.dbo.ilines
                 ON
                    dbo.product.keycode = dbo.ilines.part
                    AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )
                 WHERE
                    (dbo.iLines.Prefix = ''i'' OR dbo.iLines.Prefix is null)
                 group by 
                    dbo.ilines.pg,
                    dbo.product.keycode,
                    dbo.ilines.prefix,
                    dbo.product.pg
                 order by sales6months desc') i
RIGHT JOIN
dbo.OldParetoAnalysis
on
i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part
AND (i.pg = @pgParam or (i.pg is null AND i.ppg  = @pgParam))
INNER JOIN
dbo.NewParetoAnalysis
ON
dbo.OldParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS =   dbo.NewParetoAnalysis.Part

LEFT JOIN
OPENQUERY(SACBAUTO, 'SELECT                      
                    dbo.product.Keycode,
                    dbo.aLines.Pg,
                    SUM(COALESCE(dbo.aLines.Qty, 0)) as lostsales6months,
                    dbo.aLines.Prefix 
                 FROM 
                    Autopart.dbo.product
                 LEFT OUTER JOIN
                    Autopart.dbo.alines
                 ON
                    dbo.product.keycode = dbo.alines.part
                    AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )
                 WHERE
                    (dbo.aLines.Prefix = ''d'' OR dbo.aLines.Prefix is null)
                 group by 
                    dbo.alines.pg,
                    dbo.product.keycode,
                    dbo.alines.prefix
                 order by lostsales6months desc') a
ON
dbo.NewParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS = a.keycode
WHERE(i.pg = @pgParam or (i.pg is null AND i.ppg  = @pgParam) AND dbo.NewParetoAnalysis.Pareto is not null)
GROUP BY
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.keycode,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto
ORDER BY
dbo.OldParetoAnalysis.Pareto asc
4

8 回答 8

5

以下条件过滤掉任何right join失败的行:

dbo.ilines.part = 'BK939'

要修复它,请将条件移至联接:

RIGHT JOIN
   dbo.product  
ON
   dbo.product.keycode = dbo.ilines.part                 
   and dbo.ilines.prefix = 'i'
   and dbo.ilines.part = 'BK939'
where  
   ([datetime] > dateadd(month, -6, getdate()))

假设[datetime]是 的一列product,您可以将其留在where子句中。

于 2012-04-16T11:56:14.123 回答
3

我会从你想要的桌子和我自己做的工作开始joins。你说你想要product。为什么不从那张桌子开始,然后拿一张LEFT JOIN去呢iLines

也许是这样的:

SELECT 
    dbo.product.keycode AS part,
    dbo.iLines.Pg,
    SUM(dbo.iLines.Qty) as sales6months,
    dbo.iLines.Prefix       
FROM 
   dbo.product 
LEFT JOIN dbo.ilines  
    ON dbo.product.keycode = dbo.ilines.part
    AND dbo.ilines.prefix = 'i'
    and dbo.ilines.part = 'BK939'                 

where
    ([datetime] > dateadd(month, -6, getdate()))

group by 
   dbo.ilines.pg,
   dbo.product.keycode,
   dbo.ilines.prefix

order by sales6months desc

我不知道该[datetime]列是来自product表还是来自ilines表。如果它来自product表格,那么上面的可能会适用。如果没有,那么也将其放入LEFT JOIN。像这样:

LEFT JOIN dbo.ilines  
        ON dbo.product.keycode = dbo.ilines.part
        AND dbo.ilines.prefix = 'i'
        and dbo.ilines.part = 'BK939' 
        AND ([datetime] > dateadd(month, -6, getdate()))

编辑

根据您的描述,您想要一个FULL OUTER JOIN. 所以这个连接将是:

LEFT JOIN
dbo.OldParetoAnalysis
on
i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part

像这样:

FULL OUTER JOIN
dbo.OldParetoAnalysis
on
i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part

在 msdn 上它说:

要通过在连接结果中包含不匹配行来保留不匹配信息,请使用完全外连接。SQL Server 提供完全外连接运算符FULL OUTER JOIN,它包括两个表中的所有行,而不管另一个表是否具有匹配值。

参考这里

编辑2

您是否尝试过对 dbo.OldParetoAnalysis 进行 RIGHT JOIN?像这样:

RIGHT JOIN
dbo.OldParetoAnalysis
on
i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part

编辑3

您可以尝试的另一件事是创建一个临时表。这不是最整洁的解决方案。但也许是这样的:

CREATE TABLE #tmp 
(
    Keycode VARCHAR(100),
    Pg VARCHAR(100),
    sales6months INT,
    Prefix VARCHAR(100)
)

然后从OPENQUERY

INSERT INTO #tmp(Keycode,Pg,sales6months,Prefix)
SELECT
    i.Keycode,
    i.pg,
    i.sales6months
    i.Prefix,
FROM
    OPENQUERY(SACBAUTO, 'SELECT                     
                        dbo.product.Keycode,
                        dbo.iLines.Pg,
                        SUM(COALESCE(dbo.iLines.Qty, 0)) as sales6months,
                        dbo.iLines.Prefix 
                     FROM 
                        Autopart.dbo.product
                     LEFT OUTER JOIN
                        Autopart.dbo.ilines
                     ON
                        dbo.product.keycode = dbo.ilines.part
                        AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )/* must be this*/
                     WHERE
                        (dbo.iLines.Prefix = ''i'' OR dbo.iLines.Prefix is null)
                     group by 
                        dbo.ilines.pg,
                        dbo.product.keycode,
                        dbo.ilines.prefix
                     order by sales6months desc') i

然后我们在连接中的临时表。像这样:

SELECT
    *
FROM
    #tmp AS i
    LEFT JOIN dbo.OldParetoAnalysis
    on
    i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part
    WHERE i.pg = '40' AND i.keycode = 'BK939'

完成后记得删除临时表。像这样:

DROP TABLE #tmp

编辑4

如果您有原始存储过程,那么代码应该并且您将使用临时表解决方案,那么这可能会有所帮助:

ALTER PROCEDURE [dbo].[MyPareto]
@pgParam varchar(255)
AS

CREATE TABLE #tmp
(
    Keycode VARCHAR(100),--The type I don't know
    Pg VARCHAR(100),--The type I don't know
    sales6months INT,--The type I don't know
    Prefix VARCHAR(100)--The type I don't know
)
INSERT INTO #tmp(Keycode,Pg,sales6months,Prefix)
SELECT
    i.Keycode,
    i.pg,
    i.sales6months,
    i.Prefix
FROM
    OPENQUERY(SACBAUTO, 'SELECT                     
                        dbo.product.Keycode,
                        dbo.iLines.Pg,
                        SUM(COALESCE(dbo.iLines.Qty, 0)) as sales6months,
                        dbo.iLines.Prefix 
                     FROM 
                        Autopart.dbo.product
                     LEFT OUTER JOIN
                        Autopart.dbo.ilines
                     ON
                        dbo.product.keycode = dbo.ilines.part
                        AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )/* must be this*/
                     WHERE
                        (dbo.iLines.Prefix = ''i'' OR dbo.iLines.Prefix is null)
                     group by 
                        dbo.ilines.pg,
                        dbo.product.keycode,
                        dbo.ilines.prefix
                     order by sales6months desc') i

SELECT
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.part,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto

FROM
#tmp i
RIGHT JOIN dbo.OldParetoAnalysis 
    on i.part collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part
INNER JOIN dbo.NewParetoAnalysis 
    ON dbo.OldParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS =     dbo.NewParetoAnalysis.Part
LEFT JOIN #tmp a 
    ON dbo.NewParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS = a.part
WHERE
    i.pg = @pgParam
GROUP BY
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.part,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto
ORDER BY
    dbo.OldParetoAnalysis.Pareto asc

DROP TABLE #tmp
于 2012-04-16T11:58:13.407 回答
3

问题的根源:怀疑 where 子句标准限制了由于右连接而可能存在的数据。

可能的解决方案

  1. 在 where 子句条件上使用 or & Null
  2. 将 where 子句移动到另一个示例中已经完成的连接条件)
  3. 使用联合

这是在 where 子句上使用 null 。(修订)我们似乎都错过了从 PARTS 中提取的选择需要!不是 ilines。

SELECT dbo.product.keycode as PART,
   dbo.iLines.Pg,
   SUM(coalesce(dbo.iLines.Qty,0)) as sales6months,
   dbo.iLines.Prefix       
FROM 
   Autopart.dbo.iLines
RIGHT JOIN
   dbo.product  
ON
   dbo.product.keycode = dbo.ilines.part                 

where  (prefix = 'i' or prefix is null)
   and (([datetime] > dateadd(month, -6, getdate())) OR [datetime] is null)
   and (dbo.ilines.part = 'BK939' or dbo.ilines.part is null)

group by 
   dbo.ilines.pg,
   dbo.product.keycode,
   dbo.ilines.prefix

order by sales6months desc
于 2012-04-16T11:59:50.443 回答
2

你需要一个外部连接——像这样:

SELECT dbo.product.keycode, 
  dbo.iLines.Pg, 
  SUM(dbo.iLines.Qty) as sales6months, 
  dbo.iLines.Prefix        
FROM  
  dbo.product
  LEFT OUTER JOIN Autopart.dbo.iLines ON dbo.product.keycode = dbo.ilines.part                  

在您的查询中,您仅选择带有 的销售prefix='i',这将自动排除没有销售的产品,因此我不确定您要如何处理。

于 2012-04-16T11:56:43.940 回答
2

您仍在过滤外部连接中可能为 NULL 的内容。在 where 子句中加入 Pareto 表后:

WHERE i.pg = '40'

该列的来源(在您的 OPENQUERY 语句中)是 dbo.ILines,它是外部连接到产品的,因此如果产品未出现在 ILines 集中,它将为 NULL。您可能想尝试:

WHERE ISNULL(i.pg, '40') = '40'

当然,如果 i.pg 可以为 NULL,即使 dbo.ILines 表中存在记录,那么您可能需要在原始查询中包含 ILines 中的键并执行以下操作:

WHERE ( i.pg = '40'
        OR i.<ILinesKeyField> IS NULL
      )

这确保即使您在 dbo.ILines.Pg 中有一个 NULL 并且 NULL 字段不是由于外部连接,仍然会过滤不需要的行。

于 2012-04-19T21:26:53.233 回答
1

为什么不从产品表中选择所有并在 Autopart.dbo.iLines 上左连接?这将为您提供所有产品,然后在它们匹配和不匹配的位置加入 iLines 表。

于 2012-04-16T11:56:19.320 回答
0

这是代码,只需要从产品表和 ilines 中检查 PG!

ALTER PROCEDURE [dbo].[MyPareto32TEST]
@pgParam varchar(255)

AS
SELECT
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.keycode,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto

FROM
OPENQUERY(SACBAUTO, 'SELECT                      
                    dbo.product.Keycode,
                    dbo.iLines.Pg,
                    dbo.product.pg as ppg,
                    SUM(COALESCE(dbo.iLines.Qty, 0)) as sales6months,
                    dbo.iLines.Prefix 
                 FROM 
                    Autopart.dbo.product
                 LEFT OUTER JOIN
                    Autopart.dbo.ilines
                 ON
                    dbo.product.keycode = dbo.ilines.part
                    AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )
                 WHERE
                    (dbo.iLines.Prefix = ''i'' OR dbo.iLines.Prefix is null)
                 group by 
                    dbo.ilines.pg,
                    dbo.product.keycode,
                    dbo.ilines.prefix,
                    dbo.product.pg
                 order by sales6months desc') i
RIGHT JOIN
dbo.OldParetoAnalysis
on
i.keycode collate SQL_Latin1_General_CP1_CI_AS = dbo.OldParetoAnalysis.Part
AND (i.pg = @pgParam or (i.pg is null AND i.ppg  = @pgParam))
INNER JOIN
dbo.NewParetoAnalysis
ON
dbo.OldParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS = dbo.NewParetoAnalysis.Part

LEFT JOIN
OPENQUERY(SACBAUTO, 'SELECT                      
                    dbo.product.Keycode,
                    dbo.aLines.Pg,
                    SUM(COALESCE(dbo.aLines.Qty, 0)) as lostsales6months,
                    dbo.aLines.Prefix 
                 FROM 
                    Autopart.dbo.product
                 LEFT OUTER JOIN
                    Autopart.dbo.alines
                 ON
                    dbo.product.keycode = dbo.alines.part
                    AND ([datetime] > dateadd(month, -6, getdate()) OR [datetime] is null )
                 WHERE
                    (dbo.aLines.Prefix = ''d'' OR dbo.aLines.Prefix is null)
                 group by 
                    dbo.alines.pg,
                    dbo.product.keycode,
                    dbo.alines.prefix
                 order by lostsales6months desc') a
ON
dbo.NewParetoAnalysis.Part collate SQL_Latin1_General_CP1_CI_AS = a.keycode
WHERE(i.pg = @pgParam or (i.pg is null AND i.ppg  = @pgParam) AND dbo.NewParetoAnalysis.Pareto is not null)
GROUP BY
   i.pg,
   dbo.OldParetoAnalysis.Pareto,
   i.keycode,
   i.sales6months,
   a.LostSales6Months,
   dbo.NewParetoAnalysis.Pareto
ORDER BY
dbo.OldParetoAnalysis.Pareto asc
于 2012-04-23T11:03:58.107 回答
-1
SELECT
    dbo.iLines.Part,
    dbo.iLines.Pg,
    SUM(dbo.iLines.Qty) as sales6months,
    dbo.iLines.Prefix       
FROM Autopart.dbo.iLines
RIGHT JOIN dbo.product  
ON dbo.product.keycode = dbo.ilines.part
where  prefix = 'i'
and ([datetime] > dateadd(month, -6, getdate()))
and dbo.ilines.part = 'BK939'

group by 
    dbo.ilines.pg,
    dbo.ilines.part,
    dbo.ilines.prefix
union
SELECT
    dbo.iLines.Part,
    dbo.iLines.Pg,
    0 as sales6months,
    dbo.iLines.Prefix       
FROM Autopart.dbo.iLines
RIGHT JOIN dbo.product  
ON dbo.product.keycode = dbo.ilines.part
where  prefix = 'i'
and max([datetime]) < dateadd(month, -6, getdate())
and dbo.ilines.part = 'BK939'

group by 
    dbo.ilines.pg,
    dbo.ilines.part,
    dbo.ilines.prefix    
order by sales6months desc
于 2012-04-16T11:56:22.747 回答