2013-02-26 42 views
-4

我有2個查詢,第一:需要詢問相關的querys在SQL Server

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 
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 TOP (1) PRECIOUNIT 
FROM XCDETALLES_BODEGA 
WHERE (IDPROD = FIRSTQUERY.IDPROD) AND (XFECHA < FIRSTQUERY.FECHA) 
ORDER BY XFECHA DESC 

問:對於每一個記錄第一表我需要從替換IDPROD和FECHA後的第二個查詢中得到PRECIOUNIT。

+5

請編輯您的答案以刪除所有的CAPS,並使用代碼編輯器來格式化您的代碼,使其可讀。改正你的實際問題,讓你的問題更清楚。 – 2013-02-26 20:20:01

回答

0

您可以將第一個查詢引入CTE並將其加入到第二個查詢中。

;WITH 
FIRSTQUERY (IDPROD, CANTIDAD, MES, ANO, FECHA) 
AS 
(
    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 
    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 TOP (1) XCDETALLES_BODEGA.PRECIOUNIT 
FROM XCDETALLES_BODEGA 
LEFT JOIN FIRSTQUERY on FIRSTQUERY.IDPROD = XCDETALLES_BODEGA.IDPROD 
WHERE XCDETALLES_BODEGA.XFECHA < FIRSTQUERY.FECHA 
ORDER BY XFECHA DESC 
1

如果您想通過第二查詢返回的是列添加到第一查詢的結果,你可以簡單地將您第二次查詢到的第一個作爲相關子查詢,這樣:

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。這些轉換是絕對沒有必要的,因爲您可以反過來進行轉換。您可以不用從datetime中提取年份和月份,然後將它們轉換回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 
;