1

我试图理解一个包含 2000 个表的 xBase 类型数据库。我不想将它们全部导入 SQL Server 数据库,而是想使用“SELECT INTO tmpDBF”语句逐个导入表,然后提取我想知道的内容,例如每个列的表结构和值范围。然后,当我导入下一个表时,我希望能够对不同结构的 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。

4

2 回答 2

2

这是不可能的,原因有二。

  1. 您不能在查询中动态更改列名
  2. 您不能在单个列中混合多种数据类型。

但是为了让你得到类似于你正在寻找的东西,你可以像这样翻转问题:

SQL小提琴

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;

结果

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

结果

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

结果

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

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

于 2013-10-05T20:45:47.070 回答
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'
于 2013-10-05T20:32:14.973 回答