4

これはもともと、特定の部分で立ち往生していたため、これを実装する方法についての質問になる予定でしたが、そもそもなぜこれが起こったのかについて興味があります. 時間が変わらなければ問題にならなかった時間ではなく、日付のみを比較する必要がありました。以下のコードは、私が最初に試していたクエリを示しています

SELECT *
FROM Employee e
inner join OT_Hours o on o.Emp_ID=e.Emp_ID
inner join Position p on p.Position_ID=e.Position_ID
inner join Signup_Sheet s on s.Employee_ID=e.Emp_ID
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and Convert(Varchar(20),s.Date,101) = '07/26/2010'
and Convert(Varchar(20),o.Date,101) <='07/26/2010'
and Convert(Varchar(20),o.Date,101) > '07/26/2009'
and o.Quantity NOT IN(0.3) order by o.Date DESC

そのクエリを実行しても結果は得られませんでしたが、最後から 2 行目を削除すると 12 件の結果が返され (<=)、最後から 3 行目を削除しても最後から 2 行目を保持すると 6 件の結果が返されました (>)。データを確認したところ、これらの結果のうち 4 つが返されているはずであることがわかりました。さて、奇妙な部分です。以下は、私が現在使用しているコードです。

SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID, e.First_Name+ ' ' +e.Last_Name as Name, o.Quantity as Sum
FROM Employee e
left join OT_Hours o on o.Emp_ID=e.Emp_ID
left join Position p on p.Position_ID=e.Position_ID
left join Signup_Sheet s on s.Employee_ID=e.Emp_ID
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and Convert(Varchar(20),s.Date,101) = '07/26/2010'
and o.Date between '07/26/2009' and '07/26/2010'
and o.Quantity NOT IN(0.3) order by o.Date DESC

このクエリは結果を返しますが、o.Date が指定された日付より上または下にある場合に、他のクエリと同様にテストしました。日付が <= 16 の場合は結果が返され、> 8 の場合は結果が返されました。最後のクエリは 6 つの結果を生成しました。これは、クエリを実行している実稼働データベースではなく、それを使用しているのは私だけなので、データは変更されませんでした。なぜこれが起こったのかについての説明はありますか?それを varchar に変換することと関係があり、適切に比較できなかったと仮定していますが、それではなぜ 12 <=, 6 > になり、最終的に結果が得られないのか説明できません。また、これを実装するためのより良い方法を誰かが知っている場合は、私に知らせてください。

4

6 に答える 6

7

2 つのクエリは同じではありません。これは次のとおりです。

and o.Date between '07/26/2009' and '07/26/2010'

...次と同等です:

and o.Date >= '07/26/2009' 
and o.Date <= '07/26/2010'

BETWEEN は ANSI 標準であり、これまでに遭遇したすべてのデータベースに含まれています。

DATETIME の時間部分を指定しない場合、値はデフォルトでその日の午前 0 時 (00:00:00) から始まることに注意してください。

于 2010-07-27T16:06:52.547 に答える
5

この手法は、SQL Server Magazine 2007 年 2 月 (Datetime Calculations by Itzik Ben-Gan) から学びました。このように、この比較ではすべてが真夜中に正規化されているため、行の日付が真夜中以降であるかどうかに関係なく、「その間」は機能します。

select *
from someTable
where dateadd(day, datediff(day, 0, somedate), 0) between '07/26/2009' and '07/26/2010' 

datediff と dateadd は連携して、時刻を取り除き、日付を残します。その後、文字列リテラル、または同じ変更が行われた他の日付と比較できます。これを関数に入れることをお勧めします。

編集: OMG Ponies のコメントに基づきます。これは、日付列のインデックスを利用しません。別の方法として、他の人が言及した手法に加えて、タイム ストリッピング手法を使用することもできます。したがって、テーブルの列で行う代わりに、「before」の最後の引数で行います。次のような関数を使用できます。

CREATE FUNCTION [dbo].[fn_enddate](@enddate datetime)
RETURNS datetime AS  
BEGIN
    DECLARE @endOfDay datetime
    set @endOfDay = dateadd(millisecond, -2, dateadd(day, datediff(day, 0, @enddate) + 1, 0))
    return @endOfDay
END

これは引数 date を取り、それを翌日の午前 0 時に設定し、次に 2 ミリ秒を減算して、指定された datetime の 1 日の終わりを示します。したがって、次のことができます。

select *
from someTable
where somedate between '07/26/2009' and dbo.fn_enddate('07/26/2010')
于 2010-07-27T16:07:26.930 に答える
4

最初のクエリの最後の行から 3 行目では、2 つの文字列を比較しています。

よりも01/02/2009大きい01/01/2010

私は通常デートをしますBETWEEN '01/02/2009 00:00:00.000' AND '01/01/2010 23:59:59.997'が、より良い解決策を見るのは興味深いでしょう.

于 2010-07-27T16:08:02.373 に答える
1

あなたのデータベースが SQL Server である場合、私が行ったことは、時間を取り除くのに非常にうまく機能し、次のようなものです....

SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID, e.First_Name+ ' ' +e.Last_Name as Name, o.Quantity as Sum 
FROM Employee e 
left join OT_Hours o on o.Emp_ID=e.Emp_ID 
left join Position p on p.Position_ID=e.Position_ID 
left join Signup_Sheet s on s.Employee_ID=e.Emp_ID 
WHERE e.Eligible_OT=1 and s.Day_Shift = 1  
and p.Position_Name = 'Controller'  
and CAST(FLOOR(CAST(s.Date AS FLOAT)) AS DATETIME) = '07/26/2010' 
and CAST(FLOOR(CAST(o.Date AS FLOAT)) AS DATETIME) between '07/26/2009' and '07/26/2010' 
and o.Quantity NOT IN(0.3) order by o.Date DESC 

パラメータの設定方法に応じて、'07/26/2010'、'07/26/2009' を日時変数に格納して、同じcast(floor(cast(@datevar as float)) as datetime)操作を実行できます。

これは再投稿のようです。ここで受け入れられた回答を確認してください...日時値の時間部分を削除する方法(SQL Server)?

于 2010-07-27T16:03:00.547 に答える
1
...
AND s.Date BETWEEN '2010-07-26 00:00:00.000' AND '2010-07-26 23:59:59.997'
AND o.Date BETWEEN '2009-07-26 00:00:00.000' AND '2010-07-26 23:59:59.997'
...
于 2010-07-27T16:07:28.870 に答える
1

私の提案は、日付自体ではなく、時間をカバーするように基準を調整することです. 比較のために列を変換または操作すると、クエリでのインデックスの使用が無効になる可能性があります。

また、常に日付と日付を比較してください。それらを文字列に変換して比較しようとすると、Chris Diver が指摘するように問題が発生します。

あなたの場合、私は試してみます:

SELECT
    o.Date,
    e.Emp_ID as Emp_ID,
    e.First_Name+ ' ' +e.Last_Name as Name,
    o.Quantity as Sum
FROM
    Employee e
LEFT JOIN OT_Hours o ON o.Emp_ID = e.Emp_ID
LEFT JOIN Position p ON p.Position_ID = e.Position_ID
LEFT JOIN Signup_Sheet s ON s.Employee_ID = e.Emp_ID
WHERE
    e.Eligible_OT = 1 AND
    s.Day_Shift = 1 AND
    p.Position_Name = 'Controller' AND
    (s.Date >= @signup_date AND s.Date < DATEADD(dy, 1, @signup_date)) AND
    (o.Date >= @order_start_date AND o.Date < DATEADD(dy, 1, @order_end_date)) AND
    o.Quantity NOT IN (0.3)
ORDER BY
    o.Date DESC

パラメータまたは変数に常に時間部分がないことを確認する必要があります。

于 2010-07-27T16:18:57.697 に答える