Lude: Abfragen auf gleiche Datensatzmengen mit "Where-Filtern"

Hi,

habe eine "SQL-Frage". Und zwar geht es mir darum, bei Abfragen auf gleiche Datensatzmengen, die aber unterschiedliche "Where-Klauseln" besitzen, Code-Redundanzen zu vermeiden.

Beispiel:
select
-- lange "Select-Argumentenliste"
join
-- lange "Join-Datentabellenliste"
where
 (x = y)

select
-- lange mit der o.g. Abfrage identische "Select-Argumentenliste"
join
-- lange mit der o.g. Abfrage identische "Join-Datentabellenliste"
where
 (y = z)

-- u.s.w.

Beispielsweise stecken in einer SQL-Routine 6 solche Abfragen. Hier moechte ich den "Select-Join"-Block nur einmal haben und nicht sechsmal.

Was macht man denn da ueblicherweise? Beispielsweise CASE..WHEN..THEN bei 'T-SQL' ueberzeugt mich nicht. Temporaere Tabellen?

Gruss,
Lude

  1. Hallo Lude!

    Beispiel:
    select
    -- lange "Select-Argumentenliste"
    join
    -- lange "Join-Datentabellenliste"
    where
    (x = y)

    select
    -- lange mit der o.g. Abfrage identische "Select-Argumentenliste"
    join
    -- lange mit der o.g. Abfrage identische "Join-Datentabellenliste"
    where
    (y = z)

    Was macht man denn da ueblicherweise? Beispielsweise CASE..WHEN..THEN bei 'T-SQL' ueberzeugt mich nicht. Temporaere Tabellen?

    Eigentlich müßte es doch mit
    where (x = y) || (y = z) ...
    gehen, oder funktioniert das nicht bzw. habe ich Dein Problem nicht ganz verstanden?
    (http://www.mysql.com/doc/en/Logical_Operators.html)

    MfG
    Götz

    --
    Losung und Lehrtext für Mittwoch, 17. September 2003
    Herr, ich bin zu gering aller Barmherzigkeit und aller Treue, die du an deinem Knechte getan hast. (1.Mose 32,11)
    Wenn nun der Geist dessen, der Jesus von den Toten auferweckt hat, in euch wohnt, so wird er, der Christus von den Toten auferweckt hat, auch eure sterblichen Leiber lebendig machen durch seinen Geist, der in euch wohnt. (Römer 8,11)
    (http://www.losungen.de/heute.php3)
    1. Hi,

      Was macht man denn da ueblicherweise? Beispielsweise CASE..WHEN..THEN bei 'T-SQL' ueberzeugt mich nicht. Temporaere Tabellen?

      Eigentlich müßte es doch mit
      where (x = y) || (y = z) ...
      gehen, oder funktioniert das nicht bzw. habe ich Dein Problem nicht ganz verstanden?

      ich hatte mich schlecht ausgedrueckt. Die Routine mit den 6 Abfragen soll in Abhaengigkeit einer Bedingung (ein erhaltener Parameter, der von ihr ausgewertet wird) eine von diesen 6 Abfragen ausfuehren.

      Gruss,
      Lude

      1. Hallo Lude!

        Die Routine mit den 6 Abfragen soll in Abhaengigkeit einer Bedingung (ein erhaltener Parameter, der von ihr ausgewertet wird) eine von diesen 6 Abfragen ausfuehren.

        Ah. ok. Das hat dann aber weniger mit SQL zu tun, oder?
        Welche Abfrage ausgeführt wird entscheidet ja dann diese Routine, und nicht das SQL-Statement selbst.
        Irgendwie werd ich immer noch nciht so richtig schlau daraus ...

        MfG
        Götz

        --
        Losung und Lehrtext für Mittwoch, 17. September 2003
        Herr, ich bin zu gering aller Barmherzigkeit und aller Treue, die du an deinem Knechte getan hast. (1.Mose 32,11)
        Wenn nun der Geist dessen, der Jesus von den Toten auferweckt hat, in euch wohnt, so wird er, der Christus von den Toten auferweckt hat, auch eure sterblichen Leiber lebendig machen durch seinen Geist, der in euch wohnt. (Römer 8,11)
        (http://www.losungen.de/heute.php3)
        1. Hi,

          Ah. ok. Das hat dann aber weniger mit SQL zu tun, oder?
          Welche Abfrage ausgeführt wird entscheidet ja dann diese Routine, und nicht das SQL-Statement selbst.
          Irgendwie werd ich immer noch nciht so richtig schlau daraus ...

          SQL kommt in einigen Dialekten mit einer Programmflusskontrollsprache. Ob MySQL sowas kennt weiss ich nicht.

          (Ausserhalb von SQL, also in der umgebenden Programmlogik haette ich natuerlich kein Problem)

          Gruss,
          Lude

          1. Hi Lude,

            SQL kommt in einigen Dialekten mit einer Programmflusskontrollsprache. Ob MySQL sowas kennt weiss ich nicht.

            die Frage ist, was Du genau willst, und woran Du feststellst ob ein Parameter existiert oder nicht.

            <dein Beispiel>

            select
            -- lange "Select-Argumentenliste"
            join
            -- lange "Join-Datentabellenliste"
            where
             (x = y)

            select
            -- lange mit der o.g. Abfrage identische "Select-Argumentenliste"
            join
            -- lange mit der o.g. Abfrage identische "Join-Datentabellenliste"
            where
             (y = z)

            -- u.s.w
            </ende>

            nach welchen Kriterien entscheidest Du welche Abfrage relevant ist?

            ciao
            romy

            1. Hi,

              <mein Beispiel>

              if (@param = 'x=y')
               begin

              select
              -- lange "Select-Argumentenliste"
              join
              -- lange "Join-Datentabellenliste"
              where
               (x = y)

              end
              else if (@param = 'y=z')
               begin

              select
              -- lange mit der o.g. Abfrage identische "Select-Argumentenliste"
              join
              -- lange mit der o.g. Abfrage identische "Join-Datentabellenliste"
              where
               (y = z)

              end

              -- u.s.w
              </ende>

              Gruss,
              Lude

              1. Hi Lude,

                <dein Beispiel>
                if (@param = 'x=y')
                 begin
                select
                -- lange "Select-Argumentenliste"
                join
                -- lange "Join-Datentabellenliste"
                where
                 (x = y)
                 end
                else if (@param = 'y=z')
                 begin
                select
                -- lange mit der o.g. Abfrage identische "Select-Argumentenliste"
                join
                -- lange mit der o.g. Abfrage identische "Join-Datentabellenliste"
                where
                 (y = z)
                 end
                -- u.s.w
                </ende>

                Auch auf die Gefahr hin, dich falsch verstanden zu haben, antworte ich bescheidenerweise. ;)
                Irgendwie sieht mir das nach einer Stringverknüpfung aus, wie auch immer das in Perl geht.
                 select
                  -- lange "Select-Argumentenliste"
                 join
                  -- lange "Join-Datentabellenliste"
                 where
                  stringvernüpfung @param

                Warum sollte die Datenbank rausfinden können, welchen Parameter Du übergibst bzw. erwählst bzw. festlegst?

                ciao
                romy

                1. Hi,

                  Irgendwie sieht mir das nach einer Stringverknüpfung aus, wie auch immer das in Perl geht.

                  also, ich habe zum Beispiel sowas (bitte auf die ---MARKE--- schaun)

                  CREATE
                  procedure
                   BIZ_DATENZUGRIFFE
                    @Session_GUID uniqueidentifier,
                    @Sortierung nvarchar (32)
                   /*
                   Gibt eine Liste der Datenzugriffe zurueck, wobei die Sortierungen 'alphabetisch', 'nach_Laufzeit' und
                   'nach_DS-Laufzeit' unterstuetzt werden
                   --
                   Autor:   x
                   erstellt am:  17.02.2003
                   letzte Aenderung: 12.09.2003
                   --
                   24.02.2003  Pruefung auf 'Benutzer_GUID' und 'Recht_Name', und Logging erfolgt nun ueber
                      'SET_DATENZUGRIFF'
                   11.03.2003  Rechteabfrage auf "IsAdmin/IsUser" umgestellt
                   23.07.2003  Datenzugriffslogging nun mit 'SET_DATENZUGRIFF_START' und 'SET_DATENZUGRIFF_END'
                   09.09.2003  drei Filteroptionen implementiert
                   */
                  as
                   begin
                   --
                   declare
                    @Benutzer_GUID  uniqueidentifier,
                    @Recht_Name  nvarchar (16),
                    @Datenzugriff_GUID uniqueidentifier
                   exec
                    SET_DATENZUGRIFF_START
                     @Session_GUID  = @Session_GUID,
                     @Benutzer_GUID  = @Benutzer_GUID  output,
                     @Recht_Name  = @Recht_Name  output,
                     @Datenzugriff_SP = 'BIZ_DATENZUGRIFFE',
                     @Datenzugriff_GUID = @Datenzugriff_GUID output
                   --
                   if (dbo.IsAdmin(@Recht_Name) = 0)
                    begin
                    --
                    select
                     *
                    from
                     (
                     select
                      'benutzerspezifisch' as Zugriff,
                      Datenzugriff_SP,
                      count(*) as Anzahl,
                      min(Datenzugriff_Creation_Date) as Zuerst,
                      max(Datenzugriff_Creation_Date) as Zuletzt,
                      sum(datediff(millisecond,Datenzugriff_Creation_Date,Datenzugriff_Executed_Date)) as Laufzeit,
                      sum(datediff(millisecond,Datenzugriff_Creation_Date,Datenzugriff_Executed_Date)) / count(*) as [DS-Laufzeit]
                     from
                      DATENZUGRIFFE
                     where
                      (Datenzugriff_Benutzer_GUID = @Benutzer_GUID)
                     group by
                      Datenzugriff_SP
                     union
                     select
                      'total' as Zugriff,
                      Datenzugriff_SP,
                      count(*) as Anzahl,
                      min(Datenzugriff_Creation_Date) as Zuerst,
                      max(Datenzugriff_Creation_Date) as Zuletzt,
                      sum(datediff(millisecond,Datenzugriff_Creation_Date,Datenzugriff_Executed_Date)) as Laufzeit,
                      sum(datediff(millisecond,Datenzugriff_Creation_Date,Datenzugriff_Executed_Date)) / count(*) as [DS-Laufzeit]
                     from
                      DATENZUGRIFFE
                     group by
                      Datenzugriff_SP
                     ) [Dummy]
                    order by
                  --
                  --    ---MARKE---   HIER SCHAUEN BITTE:
                  --
                     case @Sortierung
                      when 'alphabetisch' then Datenzugriff_SP
                      when 'nach_Laufzeit' then cast(2000000000 - cast(Laufzeit as int) as nvarchar)
                      when 'nach_DS-Laufzeit' then cast(2000000000 - cast([DS-Laufzeit] as int) as nvarchar)
                     end
                    end
                   else if (dbo.IsUser(@Recht_Name) = 0)
                    begin
                    --
                    select
                     *
                    from
                     (
                     select
                      'benutzerspezifisch' as Zugriff,
                      Datenzugriff_SP,
                      count(*) as Anzahl,
                      min(Datenzugriff_Creation_Date) as Zuerst,
                      max(Datenzugriff_Creation_Date) as Zuletzt,
                      sum(datediff(millisecond,Datenzugriff_Creation_Date,Datenzugriff_Executed_Date)) as Laufzeit,
                      sum(datediff(millisecond,Datenzugriff_Creation_Date,Datenzugriff_Executed_Date)) / count(*) as [DS-Laufzeit]
                     from
                      DATENZUGRIFFE
                     where
                      (Datenzugriff_Benutzer_GUID = @Benutzer_GUID)
                     group by
                      Datenzugriff_SP
                     ) [Dummy]
                    order by
                     case @Sortierung
                      when 'alphabetisch' then Datenzugriff_SP
                      when 'nach_Laufzeit' then cast(2000000000 - cast(Laufzeit as int) as nvarchar)
                      when 'nach_DS-Laufzeit' then cast(2000000000 - cast([DS-Laufzeit] as int) as nvarchar)
                     end
                    end
                   --
                   exec
                    SET_DATENZUGRIFF_END
                     @Datenzugriff_GUID = @Datenzugriff_GUID
                   --
                   end
                  GO

                  Und mit dem "CASE-Krempel" bin ich ungluecklich. Vorher hatte ich aber 3 Queries mit identischer Datensatzmenge. Koennte noch zig weitere Beispiele geben.  :~)

                  Gruss,
                  Lude

                  1. Hi ,

                    order by
                       case @Sortierung
                        when 'alphabetisch' then Datenzugriff_SP
                        when 'nach_Laufzeit' then cast(2000000000 - cast(Laufzeit as int) as nvarchar)
                        when 'nach_DS-Laufzeit' then cast(2000000000 - cast([DS-Laufzeit] as int) as nvarchar)

                    Puh, was passt Dir eigentlich nicht an der Case-Umsetzung?
                    Letztendlich musst Du so oder so das Ganze Abfragen ob per SQL oder per Script ist ja letztendlich egal, obwohl ich glaube, dass Script performanter ist (hängt glaube ich von der Schnelligkeit des jeweiligen Servers ab)

                    In @Sortierung steht jetzt ja aphabetisch drin, warum ist der Inhalt dieser Variable nicht gleich 'Datenzugriff_SP' ? (Für die anderen Variablen genauso) Und in dem Statement sortierst Du praktisch nach @Sortierung.

                    Oder Du fragst es vorher in einem If-Else-Statement ab und generierst DIe eine Variable Sortierung, die dann den gewünschten Wert enthält.

                    order by @Sortierung

                    Mehr fällt mir jetzt auch nicht ein.

                    ciao
                    romy

                    1. Hi, romy,

                      Hi ,

                      order by
                         case @Sortierung
                          when 'alphabetisch' then Datenzugriff_SP
                          when 'nach_Laufzeit' then cast(2000000000 - cast(Laufzeit as int) as nvarchar)
                          when 'nach_DS-Laufzeit' then cast(2000000000 - cast([DS-Laufzeit] as int) as nvarchar)
                      Puh, was passt Dir eigentlich nicht an der Case-Umsetzung?

                      so ziemlich alles. Der Wert '2000000000', der soz. den maximal moeglichen integer-Wert definiert und der notwendig ist um eine absteigende Sortierung zu erreichen. Dann die Typumwandlungen. Dann, dass es mir nicht ohne weitere "Tricks" moeglich ist mehrere Argumente an die 'order by'-Klausel zu uebergeben.

                      Letztendlich musst Du so oder so das Ganze Abfragen ob per SQL oder per Script ist ja letztendlich egal, obwohl ich glaube, dass Script performanter ist (hängt glaube ich von der Schnelligkeit des jeweiligen Servers ab)

                      "Script" heisst umgebende Programmlogik und kann deshalb nicht performanter sein. Ausserdem habe ich die saubere Trennung zwischen Datenzugriff und "Programmlogik" gerne.

                      In @Sortierung steht jetzt ja aphabetisch drin, warum ist der Inhalt dieser Variable nicht gleich 'Datenzugriff_SP' ? (Für die anderen Variablen genauso) Und in dem Statement sortierst Du praktisch nach @Sortierung.

                      Wenn ich mit vorkompilierten Prozeduren arbeite, kann ich in die 'order by'-Klausel oder in die 'where'-Klausel keine Variablen setzen.

                      Oder Du fragst es vorher in einem If-Else-Statement ab und generierst DIe eine Variable Sortierung, die dann den gewünschten Wert enthält.

                      s.o.

                      Beschaeftige Dich doch mal mit serverseitig gespeicherten Datenzugriffsprozeduren. Ist ganz interessant. Allerdings kann das MySQL wohl nicht!?

                      Gruss,
                      Lude