3

LEFT JOIN右の表の条件で使用しようとしていますが、多くの問題が発生しています。

私は2つのテーブルを持っています:

  1. projects{project_id,start_date}
  2. projectForeCast{project_id,year_number,month_number,hours}

先週開かれたすべてのプロジェクトと、先月記録された時間を取得しようとしています。

SELECT      dbo.Project.PROJECT_ID, dbo.ProjectForeCast.HOURS AS F0
FROM         dbo.Project LEFT JOIN  dbo.ProjectForeCast ON dbo.Project.PROJECT_ID = dbo.ProjectForeCast.PROJECT_ID
WHERE   (dbo.ProjectForeCast.YEAR_NUMBER = DATEPART(YYYY, DATEADD(MM, 0, DATEADD(WK, - 1, GETDATE())))) AND 
                      (dbo.ProjectForeCast.MONTH_NUMBER = DATEPART(MM, DATEADD(MM, 0, DATEADD(WK, - 1, GETDATE())))) AND 
                      (DATEPART(WK,dbo.Project.START_DATE) = DATEPART(WK, DATEADD(WK, - 1, GETDATE())))AND
                      (DATEPART(YYYY,dbo.Project.START_DATE) = DATEPART(YYYY, DATEADD(WK, - 1, GETDATE())))

projectForeCastうまく機能していますが、プロジェクトに最後の記録がない場合、プロジェクトmonth_numberをまったく取得できません。F0この場合、列に空のセルまたはnullを取得したい。これが私が試した理由ですLEFT JOINが、うまくいきませんでした。

4

6 に答える 6

3

私の以前の経験として、SQL クエリを次のように記述します。

SELECT p.PROJECT_ID, pfc.HOURS AS F0
FROM 
(   SELECT dbo.Project.PROJECT_ID FROM dbo.Project q 
    WHERE (DATEPART(WK,dbo.Project.START_DATE) = DATEPART(WK, DATEADD(WK, - 1, GETDATE())))AND
    (DATEPART(YYYY,dbo.Project.START_DATE) = DATEPART(YYYY, DATEADD(WK, - 1, GETDATE())))
) p
LEFT JOIN  
(   SELECT dbo.ProjectForeCast.HOURS FROM dbo.ProjectForeCast 
    WHERE (dbo.ProjectForeCast.YEAR_NUMBER = DATEPART(YYYY, DATEADD(MM, 0, DATEADD(WK, - 1, GETDATE())))) AND 
    (dbo.ProjectForeCast.MONTH_NUMBER = DATEPART(MM, DATEADD(MM, 0, DATEADD(WK, - 1, GETDATE()))))
) pfc
ON p.PROJECT_ID = pfc.PROJECT_ID

または、SQL ステートメントが読みやすくなるテーブル エイリアスを使用します。

SELECT p.PROJECT_ID, pfc.HOURS AS F0
FROM 
(   SELECT pr.PROJECT_ID FROM dbo.Project pr 
    WHERE (DATEPART(WK,pr.START_DATE) = DATEPART(WK, DATEADD(WK, - 1, GETDATE())))AND
    (DATEPART(YYYY,pr.START_DATE) = DATEPART(YYYY, DATEADD(WK, - 1, GETDATE())))
) p
LEFT JOIN  
(   SELECT pf.HOURS FROM dbo.ProjectForeCast pf
    WHERE (pf.YEAR_NUMBER = DATEPART(YYYY, DATEADD(MM, 0, DATEADD(WK, - 1, GETDATE())))) AND 
    (pf.MONTH_NUMBER = DATEPART(MM, DATEADD(MM, 0, DATEADD(WK, - 1, GETDATE()))))
) pfc
ON p.PROJECT_ID = pfc.PROJECT_ID

上記のクエリで正しい結果が得られると思います。

于 2012-05-06T19:44:02.690 に答える
0

whereステートメントでプロジェクト予測を参照する場所でNULlをチェックする必要があります。

結合は機能していますが、2 番目のテーブルは null 値を取得しています。COALESCE または IS NULL を使用してください。

于 2012-05-06T12:41:53.407 に答える
0

LEFT JOINまたはを実行すると、条件を節RIGHT JOINに入れるか節に入れるかによって違いが生じます。JOINWHERE

例を含む詳細な説明については、この回答を確認してください:
What is the difference in these two queries as gets two different result set?

--> 行を持たないプロジェクトも取得したい場合は、句の代わりにprojectForeCast条件全体を句に入れる必要があります。JOINWHERE

于 2012-05-06T12:58:05.907 に答える
0

LEFT JOIN はプロジェクト テーブルからすべてのレコードを返すため、問題は WHERE 句にあり、問題は先週 DATEPART 'WEEK' を使用していることだと思います。代わりに、「ISOWEEK」を使用するか、SQL2008 より前に自分で計算する必要があります。

DECLARE @TodayDayOfWeek INT
DECLARE @EndOfPrevWeek DateTime
DECLARE @StartOfPrevWeek DateTime

--get number of a current day (1-Monday, 2-Tuesday... 7-Sunday)
SET @TodayDayOfWeek = datepart(dw, GetDate())
--get the last day of the previous week (last Sunday)
SET @EndOfPrevWeek = DATEADD(dd, -@TodayDayOfWeek, GetDate())
--get the first day of the previous week (the Monday before last)
SET @StartOfPrevWeek = DATEADD(dd, -(@TodayDayOfWeek+6), GetDate())

この理論をテストするには、LEFT JOIN を削除して、プロジェクト テーブルと関連する where 句のみを残します。同じプロジェクト リストが表示されます。

もう 1 つの演習は、個々の日付部分を選択して、それらが適切に一致することを確認することです。DATEPART(WK...)期待した結果が得られないことがわかると思います。

注意すべきもう 1 つの点は、1 週間を差し引いているため、月曜日と火曜日に実行した場合に異なる結果が得られることです。あなたが「先週」と言うとき、文字通りToday - 7を意味しますか、それともSun-Satのように先週を意味しますか?

このクエリを試して、問題が解決するかどうかを確認してください。

DECLARE @Today DATETIME,
        @TodayDayOfWeek INT, 
        @EndOfPrevWeek DATETIME, 
        @StartOfPrevWeek DATETIME, 
        @MonthPart1 INT,
        @MonthPart2 INT,
        @YearPart1 INT,
        @YearPart2 INT 

-- get a date range consisting of 'last week'
SET @Today = GETDATE()
--get number of a current day (1-Monday, 2-Tuesday... 7-Sunday) 
SET @TodayDayOfWeek = datepart(dw, @Today) 
--get the last day of the previous week (last Sunday) 
SET @EndOfPrevWeek = DATEADD(dd, -@TodayDayOfWeek, @Today) 
--get the first day of the previous week (the Monday before last) 
SET @StartOfPrevWeek = DATEADD(dd, -(@TodayDayOfWeek+6), @Today) 

--last week could span months or even years (i.e. Dec/Jan)
SET @MonthPart1 = DATEPART(MM, @StartOfPrevWeek)
SET @MonthPart2 = DATEPART(MM, @EndOfPrevWeek)

SET @YearPart1 = DATEPART(YYYY, @StartOfPrevWeek)
SET @YearPart2 = DATEPART(YYYY, @EndOfPrevWeek)

SELECT      
            dbo.Project.PROJECT_ID, 
            dbo.ProjectForeCast.HOURS AS F0
FROM         
            dbo.Project 
LEFT JOIN   dbo.ProjectForeCast ON dbo.Project.PROJECT_ID = dbo.ProjectForeCast.PROJECT_ID
WHERE       dbo.ProjectForeCast.YEAR_NUMBER IN (@YearPart1, @YearPart2) 
AND         dbo.ProjectForeCast.MONTH_NUMBER IN (@MonthPart1, @MonthPart2) 
AND         dbo.Project.START_DATE BETWEEN @StartOfPrevWeek AND @EndOfPrevWeek
于 2012-05-06T13:02:10.783 に答える