2016-07-15 23 views
0
Werte

I SQL Server 2012.SQL Server-Abfrage alle Spalten eines bestimmten Typs auswählen und zeigt auch seine max

Der erste Teil meiner Abfrage verwenden bereits in diesen thread beantwortet. Aber ich möchte auch eine zweite Spalte, die den entsprechenden Maximalwert dieser Spalte in der entsprechenden Tabelle anzeigt.

Ich habe diesen Ansatz versucht: Verwenden Sie eine Funktion, die Tabellenname und Spaltenname als Parameter akzeptiert und den Maximalwert zurückgibt. Es ist jedoch illegal, dynamisches SQL von einer Funktion zu verwenden. Außerdem kann ich anscheinend keine Funktion innerhalb einer SELECT-Abfrage aufrufen.

Ich habe auch versucht, gespeicherte Prozedur zu verwenden, aber ich kann nicht herausfinden, wie Sie es aufrufen und verwenden. Bitte schlagen Sie alternative Wege vor, um dies zu erreichen.

Ich bin neu in SQL Server.

Dank

Antwort

0

Sie können die folgenden SP verwenden und pro Ihre Notwendigkeit zu verbessern,

CRETE PROCEDURE Getmaxtablecolval 
AS 
    BEGIN 
     CREATE TABLE #t 
     (
      tablename VARCHAR(50), 
      columnname VARCHAR(50), 
      id   INT, 
      counts  INT 
     ) 

     INSERT INTO #t 
     SELECT table_name [Table Name], 
      column_name [Column Name], 
      NULL, 
      NULL 
     FROM information_schema.columns 
     WHERE data_type = 'INT' 

     BEGIN TRAN 

     DECLARE @id INT 

     SET @id = 0 

     UPDATE #t 
     SET @id = id = @id + 1 

     COMMIT TRAN 

     DECLARE @RowCount INT 

     SET @RowCount = (SELECT Count(0) 
         FROM #t) 

     DECLARE @I INT 

     SET @I = 1 

     DECLARE @Counter INT 
     DECLARE @TName VARCHAR(50) 
     DECLARE @CName VARCHAR(50) 
     DECLARE @DynamicSQL AS VARCHAR(500) 

     WHILE (@I <= @RowCount) 
     BEGIN 
      SELECT @TName = tablename 
      FROM #t 
      WHERE id = @I 

      SELECT @CName = columnname 
      FROM #t 
      WHERE id = @I 

      SET @DynamicSQL = 'Update #T Set Counts = ' 
           + '(Select ISNull(Max(' + @CName + '), 0) From ' 
           + @TName + ') Where Id = ' 
           + CONVERT(VARCHAR(10), @I) 

      --PRINT @DynamicSQL 
      EXEC (@DynamicSQL) 

      SET @I = @I + 1 
     END 

     SELECT * 
     FROM #t 
    END 

go 

Getmaxtablecolval 
+0

Ok! Du benutzt also einen temporären Tisch! Das ist ein netter Ansatz!Aber Sie erstellen zuerst die Tabelle mit den Spalten- und Tabellennamen, und dann führen Sie eine Schleife aus, um die Maximalwerte zu füllen. Gibt es einen Weg, es ** auf einmal ** zu tun? Oder ohne einen temporären Tisch? – MercuryX

+0

Hmm wir brauchen eine (temporäre) Tabelle, um eine dynamische Abfrage zu erstellen, da das Ergebnis nicht zu einer einzelnen Tabelle gehört. Da wir uns durchschleifen müssen, können wir es nicht ** auf einmal erstellen **. Fühlen Sie sich frei, eine Nachricht für weitere Fragen zu hinterlassen. – Lucky

0

Sie ein Verfahren aus diesem erstellen:

CREATE PROCEDURE GET_COLUMNS_WITH_MAX_VALUE 

    @COLUMN_TYPE NVARCHAR(50) 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- DUMMY VARIABLE TO COPY STRUCTURE TO TEMP 
     DECLARE @DUMMY TABLE 
    (
     TABLE_NAME NVARCHAR(50), 
     COLUMN_NAME NVARCHAR(50), 
     MAX_VALUE NVARCHAR(MAX) 
    ) 

    -- CREATE TEMP TABLE FOR DYNAMIC SQL 
    SELECT TOP 0 * INTO #TABLE FROM @DUMMY 

    INSERT INTO #TABLE 
    (TABLE_NAME, COLUMN_NAME) 
    SELECT TABLE_NAME, COLUMN_NAME 
    FROM information_schema.columns where data_type = @COLUMN_TYPE 

    DECLARE @TABLE_NAME VARCHAR(50) -- database name 
    DECLARE @COLUMN_NAME VARCHAR(256) -- path for backup files 

    DECLARE db_cursor CURSOR FOR 
    SELECT TABLE_NAME, COLUMN_NAME 
    FROM #TABLE 

    OPEN db_cursor 
    FETCH NEXT FROM db_cursor INTO @TABLE_NAME, @COLUMN_NAME 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

    DECLARE @SQL NVARCHAR(MAX) = 'UPDATE #TABLE SET MAX_VALUE = (SELECT MAX([' + @COLUMN_NAME + ']) FROM [' + @TABLE_NAME + ']) ' 
           + 'WHERE [COLUMN_NAME] = ''' + @COLUMN_NAME + ''' AND TABLE_NAME = ''' + @TABLE_NAME + ''''; 
    PRINT @SQL 
    EXEC (@SQL) 

    FETCH NEXT FROM db_cursor INTO @TABLE_NAME, @COLUMN_NAME 

    END 

    CLOSE db_cursor 
    DEALLOCATE db_cursor 


    SELECT * FROM #TABLE 

    DROP TABLE #TABLE 

END 
GO 

Verbrauch:

EXEC GET_COLUMNS_WITH_MAX_VALUE 'INT' 

Ergebnisse:

TABLE1  ID  50 
TABLE2  ID  100 
TABLE3  CarID  20 
TABLE4  StudentID 30 
+0

Schön! Ähnliche Vorgehensweise wie @Lucky. Aber ich mag die Tatsache, dass Sie einen Cursor verwendet haben. Außerdem ist es süß, dass der Datentyp als Parameter an die gespeicherte Prozedur übergeben werden kann. :) Noch einmal, kann es auf einmal und ohne einen temporären Tisch gemacht werden? – MercuryX

+0

@MercuryX Es ist nicht möglich, eine dynamische Abfrage basierend auf den Werten einer Zeile in einer einzelnen Abfrage zu erstellen. 'SELECT MAX (ColumName)' muss zu einem gültigen Spaltennamen kompiliert werden. Es kann nicht auf dem Wert einer anderen Spalte basieren. – user3185569

+0

Ja, das stimmt tatsächlich! Ich denke, ich mag deine Antwort :) – MercuryX

1

Ich denke, die einfachste Lösung Verfahren gespeichert werden würde. Soweit ich weiß:

  • Dynamisches SQL kann nicht in Funktionen
  • dynamische SQL in OPENROWSET
  • kann nicht

ich zusätzlich gestellt werden, wenn Sie eine solche Prozedur schreiben:

  • von Namen Beware Leerzeichen enthalten, qoutes (SQL-Injection möglich)
  • MAX (Spalte) auf nicht-indizierte Spalten würde Scan werden (kann sehr langsam sein)
  • Tabellen- und Spaltennamen in differend Schemata dupliziert (platziert werden können)

Id Duplikate und Leistung ist kein Problem, nehmen Sie einen Blick auf die folgenden Ausschnitt:

CREATE PROC FindMaxColumnValues 
    @type sysname = '%', 
    @table sysname = '%' 
AS 
DECLARE @result TABLE (TableName sysname, ColumnName sysname, MaxValue NVARCHAR(MAX)) 

DECLARE @tab sysname 
DECLARE @col sysname 
DECLARE cur CURSOR FOR 
    SELECT TABLE_NAME TableName, COLUMN_NAME [Column Name] 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE DATA_TYPE LIKE @type and TABLE_NAME LIKE @table 

OPEN cur 

FETCH NEXT FROM cur INTO @tab, @col 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    DECLARE @sql nvarchar(MAX) = 'SELECT '+QUOTENAME(@tab,'''')+' [TableName], '+QUOTENAME(@col, '''')+' [ColumnName], MAX('+QUOTENAME(@col)+') FROM '+QUOTENAME(@tab) 
    INSERT INTO @result EXEC(@sql) 
    FETCH NEXT FROM cur INTO @tab, @col 
END 

CLOSE cur 
DEALLOCATE cur 

SELECT * FROM @result 

Proben:

--MAX of INT's 
EXEC FindMaxColumnValues 'INT' 
--MAX of INT's in tables matching 'TestTab%' 
EXEC FindMaxColumnValues 'INT', 'TestTab%' 
--MAX of ALL columns 
EXEC FindMaxColumnValues 

Ergebnisse:

TableName ColumnName MaxValue 
IdNameTest ID   2 
TestTable ID   5 
TestTable Number  3 

TableName ColumnName MaxValue 
TestTable ID   5 
TestTable Number  3 

TableName  ColumnName MaxValue 
UpdateHistory UpdateTime 2016-07-14 12:21:37.00 
IdNameTest  ID   2 
IdNameTest  Name   T2 
TestTable  ID   5 
TestTable  Name   F 
TestTable  Number  3 
+0

Dyl die 3 Punkte, die Sie in der "zusätzlich" Abschnitt erwähnt, ist wirklich hilfreich. Die Datenbank, die ich habe, hat tatsächlich ** gleiche Tabellennamen und Spaltennamen, aber in verschiedenen Schemata **. Es gibt viele Einträge, daher mache ich mir Sorgen über die Verwendung von MAX. Und die Injektion ist immer ein Problem, aber alle Nomenklatur in meinem Setup hat keinen Platz oder andere Sonderzeichen. – MercuryX