2009-04-02 4 views
7

ho due tabelle:query SQL per escludere i record se corrisponde a una voce in un'altra tabella (come ad esempio le date delle vacanze)

applicazione
applicationID (int)
applicationname (varchar)
isavailable (bit)

e

Vacanze
ApplicationID (int)
holidaydate (datetime)

ho bisogno di ottenere il IsAvailable bandiera per ogni applicationname ma deve restituire solo se il giorno, se non è una vacanza. Il flag è disponibile flag è indipendente dalle festività - è impostato solo se esistono problemi a livello di sistema, non su una pianificazione impostata.

inizialmente ho avuto qualcosa di simile:

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) 

ma che stava tornando record, anche se oggi è stata una vacanza perché le altre date delle vacanze non equivalgono oggi.

ho cercato

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

(è su SQL Server 2005, quindi non c'è nessun tipo di Data quindi devo convertirlo)

ma ancora una volta, stava tornando record, anche se oggi è stata una vacanza. Come posso strutturare questa query usando una clausola "not in" o "except" (o qualcos'altro) per restituire un record solo se oggi non è una vacanza?

Aggiornamento

Non ho bisogno di un elenco di tutti applicationName che non hanno una vacanza - Ho bisogno di un record per l'apps.applicationname specificato. Le risposte qui sotto restituiscono solo i nomi delle applicazioni che non hanno una vacanza in data odierna. La query dovrebbe restituire il flag isavailable se non è una festività, oppure non restituire alcun record se si tratta di una festività. Non mi importa delle altre applicazioni.

Inoltre, cosa succede se ho aggiunto una tabella come:

HoursOfOperations
applicationID (int)
mondayopen (datetime)
mondayclose (datetime)
tuesdayopen (datetime)
tuesdayclose (datetime)
// apre e chiude per tutti i sette giorni della settimana

Posso partecipare a tutte e tre queste tabelle per restituire un record solo se è nelle ore del giorno indicato e non è una vacanza?Devo farlo in query separate?

risposta

14

la seguente query dovrebbe ottenere un elenco di applicazioni che non hanno una vacanza definita per la data corrente.

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

Fondamentalmente quello che facciamo è selezionare tutto dove non ha una corrispondenza.

+0

Fornisce tutte le applicazioni che non hanno una festività definita, ma ho bisogno del flag isavailable per solo l'apps.applicationname specificata. Non voglio dover scorrere l'elenco dopo la query. Inoltre, cosa succede se devo unirmi a un altro tavolo? Non riesco a combinare la clausola where and where not –

+0

Tai - basta aggiungere una clausola aggiuntiva. AND apps.AppName = 'la tua applicazione'. Puoi aggiungere tutti i join necessari, –

+0

Ho aggiornato l'esempio per te per mostrarti come limitare il nome dell'app, assumendo un parametro di @AppName –

4

È possibile utilizzare "DOVE NON ESISTE":

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

sto facendo il cast lì per troncare il getdate() per richiamare solo la data. Non ho provato quella domanda esatta, ma penso che farà il lavoro per te.

+0

Darn! Mi hai battuto per 55 secondi .... :-) –

+0

Questo ha lo stesso problema della risposta di Michael Sellers - Questo fornisce a tutte le applicazioni che non hanno una vacanza definita, ma ho bisogno del flag isavailable per solo le app specificate. Nome dell'applicazione. –

+0

Siamo spiacenti, non pensavo che sarebbe stato un problema poiché la tua query originale includeva già il test per ApplicationName = @appname. Ho pensato che tu sapessi come farlo. –

2

fare qualcosa di simile:

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

Naturalmente sarebbe molto più semplice e veloce con SQL Server 2008 del tipo di dati "DATA", o se è possibile memorizzare giorno, mese, anno in "Vacanze" separatamente.

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, solo per essere diverso, come su qualcosa di simile:

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 

sostanza, si sta unendo le tabelle in base applicationID e la data corrente. Poiché si tratta di un join di sinistra, avrai sempre tutte le applicazioni che corrispondono a @appname, quindi dovrai solo filtrare i risultati che ottengono una corrispondenza in base alla data della festività che corrisponde alla data corrente. Supponendo che applicationname sia univoco, si otterrà sempre una singola riga dove la metà destra del join è nullo, a meno che la data corrente non corrisponda a una festività, nel qual caso la query non restituirà alcun risultato.

Non so come si accumula con le altre soluzioni per quanto riguarda le prestazioni; Credo che i join dovrebbero essere più veloci delle subquery, ma probabilmente dipende da una varietà di fattori, quindi YMMV.

+0

Matt - Nella maggior parte dei casi, le prestazioni sono quasi le stesse. Sembra che questo utente abbia bisogno solo di una singola applicazione, quindi il percorso della subquery potrebbe essere un po 'più veloce ... –

+0

Venditori Mitchel - Ho sempre pensato che il problema con le sottoquery fosse che venivano ripetute per ogni riga, ma vedo che cosa sei tu sto dicendo Tutto ciò che so veramente sulle prestazioni è che se in un determinato caso è importante, dovrei semplicemente misurarlo. ;) – Matt

+0

E l'approccio "dove non esiste" è sicuramente più leggibile in ogni caso. – Matt

0

Che dire di questo:

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'" dovrebbe essere sostituito da un identificatore di variabile e "DataCorrente()" con la specifica funzione di sistema per restituire la data corrente.

Acclamazioni

/a