如果您希望将第二个查询返回的列添加到第一个查询的结果中,您可以简单地将第二个查询作为相关子查询合并到第一个查询中,如下所示:
SELECT
XEDETALLES_BODEGA.IDPROD,
SUM(XEDETALLES_BODEGA.CANTIDAD) AS CANTIDAD,
MONTH(XEDETALLES_BODEGA.XFECHA) AS MES,
YEAR(XEDETALLES_BODEGA.XFECHA) AS ANO,
CONVERT(DATETIME, CAST(YEAR(XEDETALLES_BODEGA.XFECHA) AS VARCHAR) + '-1-' + CAST(MONTH(XEDETALLES_BODEGA.XFECHA) AS VARCHAR), 103) AS FECHA,
(
SELECT TOP (1) PRECIOUNIT
FROM XCDETALLES_BODEGA
WHERE (XCDETALLES_BODEGA.IDPROD = XEDETALLES_BODEGA.IDPROD)
AND (XCDETALLES_BODEGA.XFECHA < CONVERT(DATETIME, CAST(YEAR(XEDETALLES_BODEGA.XFECHA) AS VARCHAR) + '-1-' + CAST(MONTH(XEDETALLES_BODEGA.XFECHA) AS VARCHAR), 103))
ORDER BY XCDETALLES_BODEGA.XFECHA DESC
) AS PRECIOUNIT
FROM XEDETALLES_BODEGA
LEFT OUTER JOIN xEGRESOS_BODEGA ON XEDETALLES_BODEGA.IDEGRESO = xEGRESOS_BODEGA.ID
WHERE (YEAR(XEDETALLES_BODEGA.XFECHA) = 2012) AND XEDETALLES_BODEGA.IDPROD <> 0
GROUP BY XEDETALLES_BODEGA.IDPROD, MONTH(XEDETALLES_BODEGA.XFECHA), YEAR(XEDETALLES_BODEGA.XFECHA)
ORDER BY XEDETALLES_BODEGA.IDPROD, MONTH(XEDETALLES_BODEGA.XFECHA), YEAR(XEDETALLES_BODEGA.XFECHA)
;
但是,此查询还有改进的余地。
首先,我将介绍较短的表别名。考虑一下这个重写:
SELECT
xed.IDPROD,
SUM(xed.CANTIDAD) AS CANTIDAD,
MONTH(xed.XFECHA) AS MES,
YEAR(xed.XFECHA) AS ANO,
CONVERT(DATETIME, CAST(YEAR(xed.XFECHA) AS VARCHAR) + '-1-' + CAST(MONTH(xed.XFECHA) AS VARCHAR), 103) AS FECHA,
(
SELECT TOP (1) PRECIOUNIT
FROM XCDETALLES_BODEGA AS xcd
WHERE (xcd.IDPROD = xed.IDPROD)
AND (xcd.XFECHA < CONVERT(DATETIME, CAST(YEAR(xed.XFECHA) AS VARCHAR) + '-1-' + CAST(MONTH(xed.XFECHA) AS VARCHAR), 103))
ORDER BY xcdXFECHA DESC
) AS PRECIOUNIT
FROM XEDETALLES_BODEGA AS xed
LEFT OUTER JOIN xEGRESOS_BODEGA AS xeg ON xed.IDEGRESO = xeg.ID
WHERE (YEAR(xed.XFECHA) = 2012) AND xed.IDPROD <> 0
GROUP BY xed.IDPROD, MONTH(xed.XFECHA), YEAR(xed.XFECHA)
ORDER BY xed.IDPROD, MONTH(xed.XFECHA), YEAR(xed.XFECHA)
;
您同意较短的别名使您的查询更具可读性吗?
另一个问题是您的分组标准,特别是这两个项目:
MONTH(xed.XFECHA), YEAR(xed.XFECHA)
它们当然使您的意图清晰,但是当您将它们重新转化为datetime
价值时,它们也会经历多次转换。现在我们也在datetime
相关子查询中使用相同的方法。这些转换是绝对不必要的,因为你可以反过来做。您可以将日期时间“向下舍入”到相应月份的开始,而不是从 a 中提取年份和月份datetime
,然后将它们转换回 a 。datetime
下面的表达式就是这样做的:
DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0)
现在,当您需要将月份和年份显示为数值时,您可以从上述表达式的结果中提取它们,因为这样会给出相同的月份和年份。所以,现在看看你的查询:
SELECT
xed.IDPROD,
SUM(xed.CANTIDAD) AS CANTIDAD,
MONTH(DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0)) AS MES,
YEAR(DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0)) AS ANO,
DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0) AS FECHA,
(
SELECT TOP (1) PRECIOUNIT
FROM XCDETALLES_BODEGA AS xcd
WHERE (xcd.IDPROD = xed.IDPROD)
AND (xcd.XFECHA < DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0))
ORDER BY xcd.XFECHA DESC
) AS PRECIOUNIT
FROM XEDETALLES_BODEGA AS xed
LEFT OUTER JOIN xEGRESOS_BODEGA AS xeg ON xed.IDEGRESO = xeg.ID
WHERE (YEAR(xed.XFECHA) = 2012) AND xed.IDPROD <> 0
GROUP BY xed.IDPROD, DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0)
ORDER BY xed.IDPROD, DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0)
;
我知道你可能在想什么。新表达式似乎使用了太多次,这并没有使查询看起来很干净,更不用说因为表达式不是那么短。这能帮上忙吗?是的,它可以。您可以使用派生表。将连接、WHERE 过滤器和必要的列(包括计算月初的表达式)放入子选择中,让您的主查询从中提取数据。将分组、排序和相关子查询留在主 SELECT 中。简而言之,这就是您最终可能得到的结果:
SELECT
s.IDPROD,
SUM(s.CANTIDAD) AS CANTIDAD,
MONTH(s.XFECHA) AS MES,
YEAR(s.XFECHA) AS ANO,
s.XFECHA,
(
SELECT TOP (1) PRECIOUNIT
FROM XCDETALLES_BODEGA AS xcd
WHERE (xcd.IDPROD = xed.IDPROD)
AND (xcd.XFECHA < s.XFECHA
ORDER BY xcd.XFECHA DESC
) AS PRECIOUNIT
FROM (
SELECT
xed.IDPROD,
xed.CANTIDAD,
DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0) AS FECHA
FROM XEDETALLES_BODEGA AS xed
LEFT OUTER JOIN xEGRESOS_BODEGA AS xeg ON xed.IDEGRESO = xeg.ID
WHERE (YEAR(xed.XFECHA) = 2012) AND xed.IDPROD <> 0
) s
GROUP BY s.IDPROD, s.XFECHA
ORDER BY s.IDPROD, s.XFECHA
;
但是,如果您使用的是 SQL Server 2005 或更高版本,则不需要派生表——您可以使用 CROSS APPLY 代替。这里:
SELECT
xed.IDPROD
SUM(xed.CANTIDAD) AS CANTIDAD,
MONTH(s.XFECHA) AS MES,
YEAR(s.XFECHA) AS ANO,
s.XFECHA,
(
SELECT TOP (1) PRECIOUNIT
FROM XCDETALLES_BODEGA AS xcd
WHERE (xcd.IDPROD = xed.IDPROD)
AND (xcd.XFECHA < s.XFECHA
ORDER BY xcd.XFECHA DESC
) AS PRECIOUNIT
FROM XEDETALLES_BODEGA AS xed
LEFT OUTER JOIN xEGRESOS_BODEGA AS xeg ON xed.IDEGRESO = xeg.ID
CROSS APPLY (
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, xed.XFECHA), 0) AS FECHA
) AS s
WHERE (YEAR(xed.XFECHA) = 2012) AND xed.IDPROD <> 0
GROUP BY xed.IDPROD, s.XFECHA
ORDER BY xed.IDPROD, s.XFECHA
;