2016-07-15 45 views
0

我使用SQL Server 2012的SQL Server查询选择某种类型的所有列,也表明

我查询的第一部分已经回答了这个thread其最大值。但是我也想要第二列显示相应表格中该列的相应最大值。

我试过这种方法:使用一个函数,它以表名和列名作为参数并返回最大值。但从函数使用动态SQL是非法的。此外,我似乎无法从一个SELECT查询中调用一个函数。

我也试过使用存储过程,但我无法弄清楚如何调用它并使用它。请建议替代方法来实现这一点。

我是SQL Server的新手。

感谢

回答

0

您可以使用下面的SP和提高它按您的需求,

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

好的!所以你正在使用临时表!这是一个不错的方法!但是,您首先使用列名和表名创建表,然后运行循环来填充最大值。有办法**一次去做**吗?或没有临时表? – MercuryX

+0

嗯,我们需要一个(temp)表来创建一个动态查询,因为结果不属于一个table.Since,因为我们需要循环直通,我们不能一次性创建它**。随意删除一条消息,以便进一步查询。 – Lucky

0

您可以创建一个过程出这一点:

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 

用法:

​​ 个

结果:

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

不错!与@Lucky类似的方法。但我喜欢你使用光标的事实。此外,它可以将数据类型作为参数传递给存储过程。 :)再一次,它可以一次完成,没有临时表吗? – MercuryX

+0

@MercuryX根据单个查询中某一行的值构建动态查询是不可能的。必须将“SELECT MAX(ColumName)”编译为有效的列名称。它不能基于另一列的值。 – user3185569

+0

是的,这是真的!我想我喜欢你的答案:) – MercuryX

1

我认为最简单的解决办法是存储过程。据我所知:

  • 动态SQL不能放置在功能
  • 动态SQL不能发生在OPENROWSET

我另外,如果你写这样的程序:

  • 谨防包含空格,qoutes(SQL注入可能的)名字的
  • MAX在非索引列(列),将需要全扫描(可能会很慢)
  • 表和列名可以被复制(放置在differend模式)

编号重复和性能是没有问题的,看看下面的代码片段:

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 

样品:

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

结果:

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你在“另外”部分提到的3点是非常有帮助的。我拥有的数据库确实具有**相同的表名和列名,但使用不同的模式**。有很多条目,所以我很担心使用MAX。注射始终是一个问题,但我的设置中的所有术语都没有空间或其他特殊字符。 – MercuryX

相关问题