APPLY右侧的聚合不能从左侧引用列

时间:2013-10-05 19:49:04

标签: sql sql-server

我试图了解一些带有2000个表的xBase类型数据库。我想使用'SELECT INTO tmpDBF'语句逐个导入表,而不是将它们全部导入SQL Server数据库,然后提取我想知道的内容,例如每个列的表结构和值范围。然后,当我导入下一个表时,我希望能够针对结构不同的tmpDBF表运行相同的查询。

我希望使用交叉应用来做到这一点,但我遇到了上述错误消息。

select cols.column_name 'Name', cols.data_type 'Type', mv.minV 'Minimum'
  from information_schema.columns cols
  cross apply (select MIN(cols.column_name) minV FROM tmpDBF ) mv
  where cols.table_name = 'tmpDBF'

有没有办法重新构建查询,还是我变成了一条死胡同?

10月6日添加:

鉴于tmpDBF

 Who     | Zip
 --------|------
 Charlie | 97689
 Foxtrot | 92143
 Delta   | 12011

我希望看到以下结果

 Name | Type    | Minimum | Maximum
 -----|---------|---------|--------
 who  | varchar | Charlie | Foxtrot
 Zip  | int     | 12011   | 96789

我意识到最小和最大列需要转换为varchars。

2 个答案:

答案 0 :(得分:2)

由于两个原因,这是不可能的。

  1. 您无法动态更改查询中的列名
  2. 您不能在一列中混合多种数据类型。
  3. 但为了得到类似于你所寻找的东西,你可以像这样解决问题:

    SQL Fiddle

    MS SQL Server 2008架构设置

    CREATE TABLE dbo.a(c1 INT, c2 INT, c3 DATE);
    
    INSERT INTO dbo.a VALUES(1,2,'2013-04-05'),(4,5,'2010-11-10'),(7,8,'2012-07-09');
    

    查询1

    SELECT 
       MIN(c1) c1_min,MAX(c1) c1_max,
       MIN(c2) c2_min,MAX(c2) c2_max,
       MIN(c3) c3_min,MAX(c3) c3_max
      FROM dbo.a;
    

    <强> Results

    | C1_MIN | C1_MAX | C2_MIN | C2_MAX |     C3_MIN |     C3_MAX |
    |--------|--------|--------|--------|------------|------------|
    |      1 |      7 |      2 |      8 | 2010-11-10 | 2013-04-05 |
    

    它为您提供单行中的所有列最小值和最大值。 (它还没有动态。和我在一起......)

    为了使它更具可读性,你可以使用这样的UNPIVOT:

    查询2

    SELECT 
       CASE X.FN WHEN 1 THEN 'MIN' ELSE 'MAX' END AS FN,
       CASE X.FN WHEN 1 THEN c1_min ELSE c1_max END AS c1,
       CASE X.FN WHEN 1 THEN c2_min ELSE c2_max END AS c2,
       CASE X.FN WHEN 1 THEN c3_min ELSE c3_max END AS c3
      FROM(
      SELECT 
         MIN(c1) c1_min,MAX(c1) c1_max,
         MIN(c2) c2_min,MAX(c2) c2_max,
         MIN(c3) c3_min,MAX(c3) c3_max
        FROM dbo.a)AGG
     CROSS JOIN (VALUES(1),(2))X(FN)
     ORDER BY X.FN;
    

    <强> Results

    |  FN | C1 | C2 |         C3 |
    |-----|----|----|------------|
    | MIN |  1 |  2 | 2010-11-10 |
    | MAX |  7 |  8 | 2013-04-05 |
    

    现在为了让它变得动态,我们必须动态构建该查询,如下所示:

    查询3

    DECLARE @cmd NVARCHAR(MAX);
    SET @cmd = 
     'SELECT CASE X.FN WHEN 1 THEN ''MIN'' ELSE ''MAX'' END AS FN'+
     (SELECT ',CASE X.FN WHEN 1 THEN '+name+'_min ELSE '+name+'_max END AS '+name
        FROM sys.columns WHERE object_id = OBJECT_ID('dbo.a')
         FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)')+
     ' FROM(SELECT '+
     STUFF((SELECT ',MIN('+name+') '+name+'_min,MAX('+name+') '+name+'_max'
        FROM sys.columns WHERE object_id = OBJECT_ID('dbo.a')
         FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'')+
     '   FROM dbo.a)AGG CROSS JOIN (VALUES(1),(2))X(FN) ORDER BY X.FN;';
    
    EXEC(@cmd);
    

    <强> Results

    |  FN | C1 | C2 |         C3 |
    |-----|----|----|------------|
    | MIN |  1 |  2 | 2010-11-10 |
    | MAX |  7 |  8 | 2013-04-05 |
    

    此查询在运行时获取表的列,动态构建相应的查询并执行它。它包含三个地方的表名('dbo.a')。如果您希望它与不同的表一起使用,则需要替换所有三个表。

答案 1 :(得分:0)

尝试类似

的内容
select cols.column_name 'Name', cols.data_type 'Type', mv.minV 'Minimum'
      from information_schema.columns cols
      cross apply (select MIN(cols.column_name) minV FROM tmpDBF 
                    WHERE tmpDBF.CommonCol = cols.CommonCol) mv
      where cols.table_name = 'tmpDBF'