2009-04-02 5 views
7

Ich habe zwei Tabellen:SQL-Abfrage Datensätze auszuschließen, wenn es einen Eintrag in einer anderen Tabelle (zB Urlaubsdaten) entspricht

Anwendung
applicationID (int)
Application (varchar)
isAvailable (Bit)

und

Urlaub
applicationID (int)
holidaydate (Datumzeit)

Ich brauche die IsAvailable Flagge für einen bestimmten Anwendungsname aber es sollte nur zurück zu bekommen, wenn der Tag, wenn kein Feiertag ist. Das isavailable Flag ist unabhängig von Feiertagen - es wird nur gesetzt, wenn es systemweite Probleme gibt, nicht nach einem festgelegten Zeitplan.

Ich hatte anfangs etwas wie:

select top 1 apps.isavailable 
from dbo.Applications apps, dbo.Holidays hol 
where apps.applicationid = hol.applicationid and 
     apps.applicationname = @appname and 
     ((datediff(dd,getdate(),hol.holidaydate)) != 0) 

aber das zurückkehrte Aufzeichnung auch wenn heute ein Feiertag war, weil die anderen Urlaubsdaten heute nicht gleich tun.

Ich versuchte

and (CONVERT(VARCHAR,getdate(),101)) not in (CONVERT(VARCHAR,hol.holidaydate,101)) 

(es ist auf SQL Server 2005, so dass es keine Art Datum, damit ich es konvertieren)

aber wieder, es zurückkehrt Aufzeichnungen auch wenn heute eine war Urlaub. Wie kann ich diese Abfrage mit einer "nicht in" - oder "außer" -Klausel (oder etwas anderem) strukturieren, um nur dann einen Datensatz zurückzugeben, wenn heute kein Feiertag ist?

aktualisieren

I, die keinen Urlaub haben keine Liste aller applicationnames brauchen - ich brauche für den angegebenen apps.applicationname einen Rekord. Die folgenden Antworten geben nur die Anwendungsnamen zurück, für die heute kein Feiertag vorhanden ist. Die Abfrage sollte das Isavailable-Flag zurückgeben, wenn es sich nicht um einen Feiertag handelt, oder andernfalls keine Datensätze, wenn es sich um einen Feiertag handelt. Die anderen Anwendungen interessieren mich nicht.

Auch wenn ich hinzugefügt eine Tabelle wie:

HoursOfOperations
applicationID (int)
mondayopen (Datumzeit)
mondayclose (Datumzeit)
tuesdayopen (Datumzeit)
tuesdayclose (datetime)
// öffnen und schließen für alle sieben Tage der Woche

Kann ich an allen drei dieser Tabellen teilnehmen, um nur einen Datensatz zurückzugeben, wenn es innerhalb der Stunden für den angegebenen Tag ist und kein Feiertag ist?Muss ich dies in separaten Abfragen tun?

Antwort

14

die folgende Abfrage sollten Sie eine Liste von Anwendungen erhalten, die für das aktuelle Datum definiert NICHT einen Urlaub haben.

SELECT apps.ApplicationName, apps.isavailable 
FROM dbo.Applications apps 
WHERE apps.ApplicationName = @AppName 
    AND NOT EXISTS 
(SELECT * 
    FROM Holidays 
    WHERE ApplicationId = apps.ApplicationId 
    AND CONVERT(VARCHAR,getdate(),101) = CONVERT(VARCHAR,holidaydate,101) 
) 

Grundsätzlich wählen wir alles aus, wo es keine Übereinstimmung gibt.

+0

Dies gibt alle Anwendungen, die keinen Feiertag definiert haben, aber ich brauche das Flag isavailable nur für den angegebenen apps.applicationname. Ich möchte die Liste nach der Abfrage nicht durchlaufen müssen. Was ist, wenn ich mich einer anderen Tabelle anschließen muss - ich kann die Wo und Wo nicht Klausel –

+0

Tai nicht kombinieren - fügen Sie einfach eine zusätzliche Klausel hinzu. AND apps.AppName = 'Ihre Anwendung'. Sie können alle erforderlichen Joins hinzufügen, –

+0

Ich aktualisierte das Beispiel für Sie, um Ihnen zu zeigen, wie Sie nach App-Name begrenzen, unter der Annahme eines Parameters von @AppName –

4

Sie können "WHERE NOT EXISTS":

SELECT * 
FROM Applications a 
WHERE NOT EXISTS (
    SELECT * 
    FROM Holidays h 
    WHERE h.ApplicationID = a.ApplicationID 
     AND HolidayDate = cast(cast(getdate() as int) as datetime) 
) 

ich die Besetzung dort mache das getdate() zurückrufen, um nur das Datum zu kürzen. Ich habe diese genaue Abfrage nicht getestet, aber ich denke, dass sie die Aufgabe für Sie erledigen wird.

+0

DARN! Du schlägst mich um 55 Sekunden .... :-) –

+0

Das hat das selbe Problem wie die Antwort von Michael Sellers - Das gibt alle Anwendungen, die keinen Feiertag definiert haben, aber ich brauche das Flag isavailable nur für die angegebenen Apps. Anwendungsname. –

+0

Entschuldigung - dachte nicht, dass dies ein Problem wäre, da Ihre ursprüngliche Anfrage bereits den Test für ApplicationName = @appname enthielt. Ich dachte, du wüsstest, wie das geht. –

2

Do etwas wie folgt aus:

SELECT (fields) FROM Application 
WHERE NOT EXISTS 
    (SELECT * FROM Holidays 
    WHERE ApplicationID = Application.ApplicationID 
    AND DAY(getdate()) = DAY(holidaydate) 
    AND MONTH(getdate()) = MONTH(holidaydate) 
    AND YEAR(getdate()) = YEAR(holidaydate) 
) 

Natürlich wäre es sehr viel einfacher und schneller mit SQL Server 2008 ist „DATE“ Datentyp, oder wenn Sie Tag speichern könnte, Monat, Jahr in „Urlaub“ separat.

Marc

1
SELECT a.isAvailable 
    FROM Application a 
WHERE NOT EXISTS (
    SELECT TOP 1 0 
     FROM Holidays b 
    WHERE a.applicationid = b.applicationid 
     AND holidaydate = $today 
) 
5

OK, nur anders zu sein, wie wäre es so etwas wie dieses:

select apps.isavailable 
from dbo.Application apps left outer join dbo.Holidays hol 
    on apps.applicationid = hol.applicationid 
    and convert(varchar(10),getdate(),101) = convert(varchar(10),hol.holidaydate,101) 
where apps.applicationname = @appname 
    and hol.applicationid is null 

Grundsätzlich sind die Tabellen auf applicationID und dem aktuellen Datum verbinden. Da es sich um eine linke Verknüpfung handelt, erhalten Sie immer alle Anwendungen, die mit @AppName übereinstimmen. Dann filtern Sie einfach alle Ergebnisse aus, die eine Übereinstimmung basierend auf dem Urlaubsdatum als aktuellem Datum erhalten. Unter der Annahme, dass der Anwendungsname eindeutig ist, erhalten Sie immer eine einzelne Zeile, in der die rechte Hälfte des Joins null ist, es sei denn, das aktuelle Datum entspricht einem Feiertag. In diesem Fall gibt die Abfrage keine Ergebnisse zurück.

Ich weiß nicht, wie es mit den anderen Lösungen leistungsmäßig stapelt; Ich glaube, Joins sollten im Allgemeinen schneller als Sub-Abfragen sein, aber das hängt wahrscheinlich von einer Vielzahl von Faktoren ab, so YMMV.

+0

Matt - In den meisten Fällen ist die Leistung in etwa gleich. Es sieht so aus, als ob dieser Benutzer nur eine einzige Anwendung benötigt, also könnte die Unterabfrage etwas schneller sein ... –

+0

Mitchel Verkäufer - Ich dachte immer das Problem mit Unteranfragen war, dass sie für jede Zeile wiederholt wurden, aber ich sehe was du ' rede. Alles, was ich über Leistung weiß, ist, dass, wenn es in einem bestimmten Fall wichtig ist, ich es einfach messen sollte. ;) – Matt

+0

Und der Ansatz "Where not exists" ist auf jeden Fall besser lesbar. – Matt

0

Was ist dieses:

SELECT 
    Application.isavailable 
FROM 
    Holidays 
RIGHT JOIN 
    Application 
ON 
    Holidays.applicationid = Application.applicationid 
WHERE 
    ((Application.applicationname='app1') AND 
    (((Holidays.holidaydate=CurrentDate()) AND (Holidays.applicationid Is Null)) OR 
    (holidays.holidaydate Is Null))); 

„‚app1‘“ sollte durch einen variablen Spezifizierer und „Currentdate()“ durch das System spezifische Funktion ersetzt werden, um das aktuelle Datum zurück.

Prost

/a