-4

最初の2つのクエリがあります:

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)

そして2番目のクエリ:

SELECT TOP (1) PRECIOUNIT
FROM XCDETALLES_BODEGA
WHERE (IDPROD = FIRSTQUERY.IDPROD) AND (XFECHA < FIRSTQUERY.FECHA)
ORDER BY XFECHA DESC

質問: 最初のテーブルのすべてのレコードについて、IDPROD と FECHA を置き換えた後、2 番目のクエリから得られた PRECIOUNIT を取得する必要があります。

4

2 に答える 2

1

2 番目のクエリによって返された列を最初のクエリの結果に追加する場合は、次のように、2 番目のクエリを相関サブクエリとして最初のクエリに組み込むことができます。

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)
;

エイリアスを短くするとクエリが読みやすくなることに同意しますか?

もう 1 つの問題は、グループ化の基準、特に次の 2 つの項目です。

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
;
于 2013-02-26T22:20:17.670 に答える
0

おそらく、最初のクエリを CTE に投入し、それを 2 番目のクエリに結合できます。

;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
于 2013-02-26T21:41:48.897 に答える