none
Lassen sich Funktionsrückgaben verwenden um per SELECT in einer Abfrage variabel auf Tabellen zuzugreifen?

    Frage

  • Hallo ihr,

    ich möchte auf einem SQL Server 2014 SP2 gerne die Tabellennamen in einer Abfrage variabel halten, z.B. wenn ich die Tabelle direkt abfrage, dann klaptt alles:

    select * from dbo.[012018_Buchungen];

    Und die Benutzerfunktion gibt genau den Wert zurück, der ein Tabellenname ist:

    select dbo.fnc_TabellenNameOpt(GETDATE());

    Das Ergebnis ist dann, wie gewünscht:

    dbo.[012018_Buchungen]

    Füge ich jedoch die Funktionen ineinander (so hätte ich eine dynamische Abfrage und keine statische), kommt eine Fehlermeldung:

    select * from dbo.fnc_TabellenNameOpt(GETDATE());
    Meldung 208, Ebene 16, Status 3, Zeile 5
    Ungültiger Objektname 'dbo.fnc_TabellenNameOpt'.


    USE [Opt_test]
    GO
    /****** Object:  UserDefinedFunction [dbo].[fnc_TabellenNameOpt]    Script Date: 13.06.2018 14:28:23 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER function [dbo].[fnc_TabellenNameOpt]
    (
    	@datum date
    )
    RETURNS varchar(100)
    AS
    BEGIN
    	DECLARE @rueckgabe varchar(100);
    	SET @rueckgabe = CONCAT('dbo.[01', YEAR(@datum), '_Buchungen]');
    	RETURN @rueckgabe
    END
    

    Hat jemand einen Tipp?

    Viele Grüße,

    Christoph


    • Bearbeitet chris_rall Mittwoch, 13. Juni 2018 14:45
    Mittwoch, 13. Juni 2018 12:55

Antworten

  • Hallo Christoph,

    da wirst Du wohl um dynamisches SQL nicht herumkommen, wobei dabei einiges zu beachten ist:

    Dynamisches SQL : Fluch Und Segen

    In der Mitte ist ein interessanter Absatz, über den Du noch einmal nachdenken solltest, falls Du überhaupt Handlungsspielraum hast:

    Gibt es also keinen anderen Ausweg als dynamisches SQL? Doch, gehen wir noch einmal einen Schritt zurück und betrachten noch einmal die Situation. Hier wird von Beginn an der falsche Ansatz verfolgt. Ihr Datenmodell ist einfach fehlerhaft. Eine Tabelle pro Monat mag in Systemen wie Access oder Flat File Datenbanken notwendig sein, um die Performance zu erhöhen, aber in SQL Server oder jedem anderen High-End RDBMS gibt es kaum einen Grund für diesen Ansatz. SQL Server und seine Konkurrenzprodukte sind entwickelt worden für den Umgang mit grossen Datenmengen und den Zugriff darauf, anhand der Schlüssel in den Daten. Jahr und Monat sollte schlicht und einfach der erste Teil des Primärschlüssels einer einzigen Umsatztabelle.


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu


    Mittwoch, 13. Juni 2018 13:01
  • Hallo Christoph,

    das geht so nicht, für Objektnamen kann man weder Variablen noch Funktionen verwenden, die muss man fest angeben. Das hilft nur dynamisches SQL mit sp_executesql (Transact-SQL)


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    • Als Antwort markiert chris_rall Mittwoch, 13. Juni 2018 14:51
    Mittwoch, 13. Juni 2018 13:03

Alle Antworten

  • Hallo Christoph,

    da wirst Du wohl um dynamisches SQL nicht herumkommen, wobei dabei einiges zu beachten ist:

    Dynamisches SQL : Fluch Und Segen

    In der Mitte ist ein interessanter Absatz, über den Du noch einmal nachdenken solltest, falls Du überhaupt Handlungsspielraum hast:

    Gibt es also keinen anderen Ausweg als dynamisches SQL? Doch, gehen wir noch einmal einen Schritt zurück und betrachten noch einmal die Situation. Hier wird von Beginn an der falsche Ansatz verfolgt. Ihr Datenmodell ist einfach fehlerhaft. Eine Tabelle pro Monat mag in Systemen wie Access oder Flat File Datenbanken notwendig sein, um die Performance zu erhöhen, aber in SQL Server oder jedem anderen High-End RDBMS gibt es kaum einen Grund für diesen Ansatz. SQL Server und seine Konkurrenzprodukte sind entwickelt worden für den Umgang mit grossen Datenmengen und den Zugriff darauf, anhand der Schlüssel in den Daten. Jahr und Monat sollte schlicht und einfach der erste Teil des Primärschlüssels einer einzigen Umsatztabelle.


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu


    Mittwoch, 13. Juni 2018 13:01
  • Hallo Christoph,

    das geht so nicht, für Objektnamen kann man weder Variablen noch Funktionen verwenden, die muss man fest angeben. Das hilft nur dynamisches SQL mit sp_executesql (Transact-SQL)


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    • Als Antwort markiert chris_rall Mittwoch, 13. Juni 2018 14:51
    Mittwoch, 13. Juni 2018 13:03
  • Hallo

    für solche Konstrukte nehme  ich immer

    @sqlstatement = 'Select * from @rueckgabe'@rueckgabe

    Execute sp_executesql  @sqlstatment

    Gruss

    Felix

    


    • Bearbeitet FelixB62 Mittwoch, 13. Juni 2018 13:19
    Mittwoch, 13. Juni 2018 13:09
  • Hallo Christoph,

    das ist mir auch klar, dass das Design nicht das beste ist. Es hilft aber nichts, da es historisch gewachsen (aufwärts migriert von einer Access DB) ist und von einem Fremdhersteller stammt. Wir müssen auf die Tabellen zugreifen und ich wollte eben dynamisches SQL vermeiden.

    Viele Grüße,

    Christoph

    Mittwoch, 13. Juni 2018 13:21
  • Hallo Olaf,

    habe es mal getestet: ja, es geht wenn ich es in eine Prozdedur kapsele:

    ALTER PROCEDURE [dbo].[prc_test]
    	@datumP date
    	AS
    BEGIN
    	SET NOCOUNT ON;
    
    	DECLARE @sqlstatement nvarchar(500);
            SET @sqlstatement = concat('select * from ',dbo.fnc_TabellenNameOpt(@datumP));
    	select @sqlstatement;
    	EXECUTE sp_executesql @sqlstatement;
    END
    Aufruf:
    DECLARE	@return_value int
    DECLARE	@datumA date
    SET @datumA = getdate()
    EXEC	@return_value = [dbo].[prc_test] @datumA;
    GO

    Gruß,

    Christoph

    • Bearbeitet chris_rall Mittwoch, 13. Juni 2018 15:56
    Mittwoch, 13. Juni 2018 15:51