none
Query con date RRS feed

  • Domanda

  • Ciao a tutti
    Un piccolo consiglio su come creare una query. Devo controllare se una camera non è prenotata in un dato periodo. Oltre a controllare tra i giorni prenotati, ho anche una tabella con i giorni in cui la camera non è disponibile.

    Come posso scrivere questa query?

    Grazie mille

    giovedì 18 luglio 2013 07:35

Risposte

  • salve,

    ti giro la mia risposta che ti ho dato su ASPItalia, per completezza di informazione...

    ---

    salve,
    usualmente e' bella cosa indicare un minimo di DDL per fare in modo che non si debba inventare tutto lo scenario e partire da una base comune di riferimento...
    detto cio', potresti ad esempio addivenire, in maniera moltro triviale, ad una ricerca simile a

    SET NOCOUNT ON;
    USE tempdb;
    GO
    CREATE TABLE dbo.Rooms (
      Room varchar(10) NOT NULL PRIMARY KEY
      );
    CREATE TABLE dbo.Booking (
      Id int NOT NULL IDENTITY PRIMARY KEY,
      Room varchar(10) NOT NULL
        CONSTRAINT fk_Booking$has$Rooms FOREIGN KEY
          REFERENCES dbo.Rooms (Room)
        ,
      Occupancy varchar(10) NOT NULL,
      Arrival date NOT NULL,
      Departure date NOT NULL
      );
    CREATE TABLE dbo.Maintenance (
      Id int NOT NULL IDENTITY PRIMARY KEY,
      Room varchar(10) NOT NULL
        CONSTRAINT fk_Maintenance$has$Rooms FOREIGN KEY
          REFERENCES dbo.Rooms (Room)
        ,
      UnavailableDate date NOT NULL,
      Task varchar(20) NOT NULL
      );
    GO
    INSERT INTO dbo.Rooms
      VALUES ('101'), ('102'), ('103');
    
    INSERT INTO dbo.Booking
      VALUES ('101', 'A', '20130725', '20130728'),
        ('101', 'B', '20130729', '20130802');
    
    INSERT INTO dbo.Maintenance 
      VALUES ('101', '20130728', 'imp.elettrico');
    GO
    DECLARE @Task varchar(10);
    DECLARE @bookFrom date, @bookTo date;
    
    SELECT @Task = '101', @bookFrom = '20130728', @bookTo = '20130729';
    
    SELECT CONVERT(bit, 0) AS [IsMaintenaceTask], b.[Occupancy] AS [Occupancy/Task]
      FROM [dbo].[Booking] b
      WHERE @bookFrom BETWEEN b.[Arrival] AND CASE WHEN b.[Arrival] = b.[Departure] THEN b.[Departure] ELSE DATEADD(DAY, -1, b.[Departure]) END
        OR DATEADD(DAY, -1, @bookTo) BETWEEN b.[Arrival] AND CASE WHEN b.[Arrival] = b.[Departure] THEN b.[Departure] ELSE DATEADD(DAY, -1, b.[Departure]) END
        OR @bookFrom < b.[Arrival] AND @bookTo > b.[Departure]
    UNION
    SELECT CONVERT(bit, 1) AS [IsMaintenaceTask], h.[Task] AS [Occupancy/Task]
      FROM [dbo].[Maintenance] h
      WHERE h.[UnavailableDate] BETWEEN @bookFrom AND DATEADD(DAY, -1, @bookTo)
    GO
    DROP TABLE dbo.Booking, dbo.Maintenance, dbo.Rooms;
    --<--------
    IsMaintenaceTask Occupancy/Task
    ---------------- --------------------
    1                imp.elettrico

    dove per il periodo specificato la camera 101 non sara' disponibile a causa di un'attivita' di manutenzione... nel caso tu ricerchi la "disponibilta'" pura della camera, ti basterebbe negare il resultset in una clausola IF NOT EXISTS (..... )

    detto cio', non "stravedo" per un'implementazione come questa, ma le tue indicazioni testuali mi hanno spinto su questa strada, ma probabilmente le ho mal interpretate....
    come ben sai, un'occupazione puo' comportare dei cambi di camera, e quindi la tabella Booking non dovrebbe contenere l'attributo [Room], che dovrebbe essere parte di altra tabella referenziante la prenotazione in oggetto...
    mi spiazza poi come sembri aver gestito le manutenzioni... per le occupazioni vere e proprie pari usare (a mio avviso correttamente) un time-frame, nell'esempio indicato dagli attributi [Arrival] e [Departure], mentre per le manutenzioni pari indicare il punto temporale giornaliero invece di un time-frame, quindi nel caso la camera 101 debba subire interventi all'impianto elettrico che ne comportino l'indisponibilita' per piu' giorni, mi pare di comprendere che saranno presenti "n" righe di indisponibilita', una per ogni giorno, con ridondanza nel caso in esame dell'attributo [Task] (ovviamente nel caso normalizzabile in altra tabella referenziata)... personalmente penso che comunque opterei per la finestra temporale e non per il momento puntuale come qui da me espresso...
    ma probabilmente non ho ben interpretato le tue indicazioni...
    saluti


    http://www.hotelsole.com/asql/index.php - DbaMgr2k - DbaMgr and further SQL Tools http://www.hotelsole.com/

    • Proposto come risposta Emiliano Musso martedì 23 luglio 2013 12:34
    • Contrassegnato come risposta SviPla mercoledì 24 luglio 2013 13:15
    lunedì 22 luglio 2013 16:22
    Moderatore

Tutte le risposte

  • Ciao,

    potresti riportare la struttura delle due tabelle? In questo modo sarà senz'altro più semplice risponderti.

    lunedì 22 luglio 2013 14:12
  • salve,

    ti giro la mia risposta che ti ho dato su ASPItalia, per completezza di informazione...

    ---

    salve,
    usualmente e' bella cosa indicare un minimo di DDL per fare in modo che non si debba inventare tutto lo scenario e partire da una base comune di riferimento...
    detto cio', potresti ad esempio addivenire, in maniera moltro triviale, ad una ricerca simile a

    SET NOCOUNT ON;
    USE tempdb;
    GO
    CREATE TABLE dbo.Rooms (
      Room varchar(10) NOT NULL PRIMARY KEY
      );
    CREATE TABLE dbo.Booking (
      Id int NOT NULL IDENTITY PRIMARY KEY,
      Room varchar(10) NOT NULL
        CONSTRAINT fk_Booking$has$Rooms FOREIGN KEY
          REFERENCES dbo.Rooms (Room)
        ,
      Occupancy varchar(10) NOT NULL,
      Arrival date NOT NULL,
      Departure date NOT NULL
      );
    CREATE TABLE dbo.Maintenance (
      Id int NOT NULL IDENTITY PRIMARY KEY,
      Room varchar(10) NOT NULL
        CONSTRAINT fk_Maintenance$has$Rooms FOREIGN KEY
          REFERENCES dbo.Rooms (Room)
        ,
      UnavailableDate date NOT NULL,
      Task varchar(20) NOT NULL
      );
    GO
    INSERT INTO dbo.Rooms
      VALUES ('101'), ('102'), ('103');
    
    INSERT INTO dbo.Booking
      VALUES ('101', 'A', '20130725', '20130728'),
        ('101', 'B', '20130729', '20130802');
    
    INSERT INTO dbo.Maintenance 
      VALUES ('101', '20130728', 'imp.elettrico');
    GO
    DECLARE @Task varchar(10);
    DECLARE @bookFrom date, @bookTo date;
    
    SELECT @Task = '101', @bookFrom = '20130728', @bookTo = '20130729';
    
    SELECT CONVERT(bit, 0) AS [IsMaintenaceTask], b.[Occupancy] AS [Occupancy/Task]
      FROM [dbo].[Booking] b
      WHERE @bookFrom BETWEEN b.[Arrival] AND CASE WHEN b.[Arrival] = b.[Departure] THEN b.[Departure] ELSE DATEADD(DAY, -1, b.[Departure]) END
        OR DATEADD(DAY, -1, @bookTo) BETWEEN b.[Arrival] AND CASE WHEN b.[Arrival] = b.[Departure] THEN b.[Departure] ELSE DATEADD(DAY, -1, b.[Departure]) END
        OR @bookFrom < b.[Arrival] AND @bookTo > b.[Departure]
    UNION
    SELECT CONVERT(bit, 1) AS [IsMaintenaceTask], h.[Task] AS [Occupancy/Task]
      FROM [dbo].[Maintenance] h
      WHERE h.[UnavailableDate] BETWEEN @bookFrom AND DATEADD(DAY, -1, @bookTo)
    GO
    DROP TABLE dbo.Booking, dbo.Maintenance, dbo.Rooms;
    --<--------
    IsMaintenaceTask Occupancy/Task
    ---------------- --------------------
    1                imp.elettrico

    dove per il periodo specificato la camera 101 non sara' disponibile a causa di un'attivita' di manutenzione... nel caso tu ricerchi la "disponibilta'" pura della camera, ti basterebbe negare il resultset in una clausola IF NOT EXISTS (..... )

    detto cio', non "stravedo" per un'implementazione come questa, ma le tue indicazioni testuali mi hanno spinto su questa strada, ma probabilmente le ho mal interpretate....
    come ben sai, un'occupazione puo' comportare dei cambi di camera, e quindi la tabella Booking non dovrebbe contenere l'attributo [Room], che dovrebbe essere parte di altra tabella referenziante la prenotazione in oggetto...
    mi spiazza poi come sembri aver gestito le manutenzioni... per le occupazioni vere e proprie pari usare (a mio avviso correttamente) un time-frame, nell'esempio indicato dagli attributi [Arrival] e [Departure], mentre per le manutenzioni pari indicare il punto temporale giornaliero invece di un time-frame, quindi nel caso la camera 101 debba subire interventi all'impianto elettrico che ne comportino l'indisponibilita' per piu' giorni, mi pare di comprendere che saranno presenti "n" righe di indisponibilita', una per ogni giorno, con ridondanza nel caso in esame dell'attributo [Task] (ovviamente nel caso normalizzabile in altra tabella referenziata)... personalmente penso che comunque opterei per la finestra temporale e non per il momento puntuale come qui da me espresso...
    ma probabilmente non ho ben interpretato le tue indicazioni...
    saluti


    http://www.hotelsole.com/asql/index.php - DbaMgr2k - DbaMgr and further SQL Tools http://www.hotelsole.com/

    • Proposto come risposta Emiliano Musso martedì 23 luglio 2013 12:34
    • Contrassegnato come risposta SviPla mercoledì 24 luglio 2013 13:15
    lunedì 22 luglio 2013 16:22
    Moderatore
  • Grazie a tutti

    In breve le tabelle potrebbro essere queste:

    Camere= id_camera

    Prenotazioni= id | id_camera | dal | al

    non_disponibile= id | id_camera | giorno

    Grazie
    • Modificato SviPla mercoledì 24 luglio 2013 11:22 trovato errore
    mercoledì 24 luglio 2013 11:10
  • La soluzione proposta da Andrea Montanari mi pare adatta al tuo caso, ricalca in maniera fedele la tua problematica.

    Un saluto

    mercoledì 24 luglio 2013 12:46