使用T-SQL生成乘法表

时间:2015-05-18 19:51:59

标签: sql-server tsql sql-server-2012

我试图在Microsoft SQL Server 2012中使用T-SQL生成乘法表,并且一直停留在宽度大于高度的情况下。只要它不成立,一切顺利,但任何时候高度越大,索引大于高度值的最后一个单元格都是NULL ...为什么这样,我怎么能克服这个?

它只是根据我的理解为高度值生成方形矩阵,但我不确定如何解决它......

DECLARE @InitialValue int, @Height int, @Width int, @ColumnNames varchar(max), @RowNames varchar(max), @sql varchar(max);
SET @InitialValue = 2;
SET @Height = 2
SET @Width = 5

SELECT
    @RowNames = COALESCE(@RowNames + ', ', '')
              + '[' + CAST(@InitialValue + number AS varchar) + ']'
FROM master..spt_values
WHERE type = 'P'
  AND number BETWEEN 0 AND @Height-2;

SELECT
    @ColumnNames = COALESCE(@ColumnNames + ', ', '')
              + '[' + CAST(@InitialValue + number AS varchar) + ']'
FROM master..spt_values
WHERE type = 'P'
  AND number BETWEEN 0 AND @Width-2;


SET @sql =
'WITH numbers AS (
  SELECT ' + CAST(@InitialValue AS varchar) + ' + number AS X
  FROM master..spt_values
  WHERE type = ''P''
    AND number BETWEEN 0 AND ' + CAST(@Height-2 AS varchar) +'
),
products AS (
  SELECT
    n1.X,
    PivotN = n2.X,
    P = n1.X * n2.X
  FROM numbers n1
    CROSS JOIN numbers n2
)
SELECT
  X, ' + @ColumnNames + '
FROM products
PIVOT (MAX(P) FOR PivotN IN (' + @ColumnNames + ')) p';
EXEC(@sql);

OUT:

X   2   3   4   5
2   4   NULL    NULL    NULL

2 个答案:

答案 0 :(得分:1)

我没有真正看过你的代码,我只是写了自己的代码,它适用于任何高度或宽度。看看:

DECLARE @InitialValue INT = 1,
        @Height INT = 1,
        @Width INT  = 5,
        @PivotColumns VARCHAR(MAX);
IF OBJECT_ID('tempdb..##NumsTable') IS NOT NULL
    DROP TABLE ##numsTable;

CREATE TABLE ##NumsTable (num INT PRIMARY KEY);

WITH CTE_Nums
AS
(
    SELECT @InitialValue AS num
    UNION ALL
    SELECT num + 1
    FROM CTE_Nums
    WHERE num <=        CASE
                        WHEN @Height > @Width
                            THEN @Height
                        ELSE @Width
                    END
)

INSERT INTO ##numsTable
    SELECT num
    FROM CTE_Nums
    OPTION (MAXRECURSION 0)

SELECT @PivotColumns = COALESCE(@PivotColumns + ',','') + QUOTENAME(num)
FROM ##numsTable
WHERE num < @InitialValue + @Width;

DECLARE @SQL NVARCHAR(MAX);
SELECT @SQL = 
N'WITH CTE_crossJoin
AS
(
SELECT  A.num           AS rowNums,
        B.num           AS colNums,
        A.num * B.num   AS result
FROM ##numsTable A
CROSS JOIN ##numsTable B
WHERE       A.num < @IV + @H
        AND B.num < @IV+ @W
)

SELECT *
FROM CTE_crossJoin
PIVOT
(
    MAX(result) FOR colNums IN (' + @pivotColumns + ')
) pvt'

EXECUTE sp_executesql @sql,N'@IV INT,@H INT,@W INT', @IV = @initialValue,@H = @Height,@W = @Width

答案 1 :(得分:0)

这是一个不同的版本:

declare @InitialValue int = 2, @Height int = 10, @Width int = 10;
declare @cols varchar(4000), @f varchar(4000), @s varchar(4000);

with cols as(select @InitialValue as w
            union all 
            select w + 1 from cols where w < @InitialValue + @Width - 1)

select 
      @cols = STUFF((SELECT '],[' + convert(varchar(10), w) FROM cols FOR XML PATH ('')) , 1, 2, '') + ']',
      @f = 'case when h.h = 1 then ''X'' else cast(h.h as char(10)) end,' + 
              STUFF((SELECT '],h.h*s.[' + convert(varchar(10), w) FROM cols FOR XML PATH ('')) , 1, 2, '') + ']'

set @s = 'with height as (
            select 1 as h
            union all 
            select h + 1 from height where h < ' + CAST(@Height as varchar(10)) +           
            '),
width as(select ' + CAST(@InitialValue as varchar(10)) + ' as w
            union all 
            select w + 1 from width where w < ' + CAST(@InitialValue + @Width - 1 as varchar(10)) +'),
spread as(select * from width pivot(max(w) for w in(' + @cols + ')) p)                      
select ' + @f + ' 
from height h
cross join spread s'

print (@s)
exec (@s)

输出:

@InitialValue int = 2,@ High int = 10,@ Wide int = 10

X   2   3   4   5   6   7   8   9   10
2   4   6   8   10  12  14  16  18  20
3   6   9   12  15  18  21  24  27  30
4   8   12  16  20  24  28  32  36  40
5   10  15  20  25  30  35  40  45  50
6   12  18  24  30  36  42  48  54  60
7   14  21  28  35  42  49  56  63  70
8   16  24  32  40  48  56  64  72  80
9   18  27  36  45  54  63  72  81  90
10  20  30  40  50  60  70  80  90  100

@InitialValue int = 2,@ Height int = 3,@ width int = 5

X   2   3   4   5
2   4   6   8   10
3   6   9   12  15

@InitialValue int = 5,@ Height int = 4,@ Width int = 3

X   5   6
2   10  12
3   15  18
4   20  24