需要根据列中的值生成n行

时间:2011-06-22 12:21:23

标签: sql-server tsql

我有下表

表A

ID | QUANTITY
------------
1  | 3
2  | 2

我需要的是

表B

ID | Ref No.
------------
1  | MyRef1
1  | MyRef2
1  | MyRef3
2  | AnotherRef1
2  | AnotherRef2

即。我需要使用与A中的数量相同的行数生成表B,并使用递增的参考号。在每一行。

我可以用游标或UDF来做,但有更优雅的解决方案吗?

7 个答案:

答案 0 :(得分:17)

我会假设

  1. MyRef等是TableA
  2. 中的一列
  3. 您有numbers表格
  4. 类似的东西:

    SELECT * INTO #TableA
    FROM
     (
        SELECT  1 AS ID, 3 AS QUANTITY, 'MyRef' AS refColumn
        UNION ALL
        SELECT 2, 2, 'AnotherRef'
    ) T
    
    
    ;WITH Nbrs ( Number ) AS (
        SELECT 1 UNION ALL
        SELECT 1 + Number FROM Nbrs WHERE Number < 99
    )
    SELECT
       A.ID, A.refColumn + CAST(N.Number AS varchar(10))
    FROM
       #TableA A
       JOIN
       Nbrs N ON N.Number <= A.QUANTITY
    

答案 1 :(得分:7)

这将在SQL Server 2005+中创建您想要的行数,但我不确定您要如何确定MyRef和AnotherRef应该是什么......

WITH
  expanded
AS
(
  SELECT id, Quantity FROM myTable

UNION ALL

  SELECT id, Quantity - 1 FROM expanded WHERE Quantity > 1
)

SELECT
  *,
  ROW_NUMBER() OVER (ORDER BY id, Quantity) AS unique_ref
FROM
  expanded
ORDER BY
  id,
  Quantity

答案 2 :(得分:2)

以下为您提供了正确的行数,但我的观察结果与@Dems相同:您如何确定MyRefAnotherRef

请注意,这至少需要SQL Server 2005

SQL语句

;WITH TableA (ID, Quantity) AS (
    SELECT  1, 3
    UNION ALL SELECT 2, 2
)
, q AS (
    SELECT  ID
            , Number = 1
            , Quantity
    FROM    TableA
    UNION ALL 
    SELECT  ID
            , Number = Number + 1
            , Quantity
    FROM    q
    WHERE   Quantity > Number
)
SELECT  ID
        , CASE WHEN ID = 1 THEN 'MyRef' + CAST(Number AS VARCHAR(1))
               WHEN ID = 2 THEN 'AnotherRef' + CAST(Number AS VARCHAR(1))
          END AS [Ref No.]
FROM    q       
ORDER BY
        ID

输出

ID  Ref No.
1   MyRef1
1   MyRef2
1   MyRef3
2   AnotherRef1
2   AnotherRef2

答案 3 :(得分:0)

单击选择按列TableA.quantity生成行。仅使用ISO / ANSI SQL标准语法2003(DB必须支持窗口功能)。

TableA定义:

|----|----------|---------------|
| id | quantity | another_value |
|----|----------|---------------|
|  1 |         3|       value_a |
|  2 |         2|       value_b |
|  3 |         6|       value_c |
|----|----------|---------------|

CREATE TABLE TableA AS
  (SELECT 1 as ID, 3 AS quantity, 'value_a' AS another_value 
  UNION SELECT 2, 2, 'value_b' 
  UNION SELECT 3, 6, 'value_c');

以下查询可用于最多1000的数量值。对于数量最多10000个,请按语句CROSS JOIN ten AS rank10000扩展查询...

SELECT 
  ROW_NUMBER() OVER(order by id) as unique_id, 
  id as original_id, 
  another_value || ROW_NUMBER() OVER (PARTITION BY id) as another_value
FROM TableA
INNER JOIN
  (SELECT row_number() OVER () AS rnum FROM
    (WITH ten AS (SELECT 1 AS id UNION SELECT 2 
         UNION SELECT 3 UNION SELECT 4 
         UNION SELECT 5 UNION SELECT 6 
         UNION SELECT 7 UNION SELECT 8 
         UNION SELECT 9 UNION SELECT 10)
     SELECT * 
     FROM ten AS rank10 
     CROSS JOIN ten AS rank100 
     CROSS JOIN ten AS rank1000
    ) helper
  ) help ON help.rnum <= TableA.quantity

SQL结果:

|-----------|-------------|---------------|
| unique_id | original_id | another_value |
|-----------|-------------|---------------|
|         1 |           1 |      value_a1 |
|         2 |           1 |      value_a2 |
|         3 |           1 |      value_a3 |
|         4 |           2 |      value_b1 |
|         5 |           2 |      value_b2 |
|         6 |           3 |      value_c1 |
|         7 |           3 |      value_c2 |
|         8 |           3 |      value_c3 |
|         9 |           3 |      value_c4 |
|        10 |           3 |      value_c5 |
|        11 |           3 |      value_c6 |
|-----------|-------------|---------------|

它应该适用于PostgreSQL,Oracle或MSSQL(在PostgreSQL 9.0上测试)

<强>编辑: 使用语句 WITH RECURSIVE 优化查询(来自MatBailie的想法):

SELECT 
  ROW_NUMBER() OVER() as unique_id, 
  id as original_id, 
  another_value || ROW_NUMBER() OVER (PARTITION BY id) as another_value
FROM 
  (WITH RECURSIVE helper AS 
    (SELECT id, quantity, another_value FROM TableA 
     UNION ALL 
     SELECT id, quantity-1, another_value FROM helper WHERE quantity > 1
    ) SELECT * FROM helper ORDER BY id, quantity
  ) TableB

答案 4 :(得分:0)

只要tblNumbers中的记录数超过TableA中找到的Quantity值的最大值,Numbers表解决方案就可以在MS Access中使用:

SELECT TableA.ID, TableA.Quantity, tblNumbers.RecNum FROM TableA LEFT JOIN tblNumbers ON tblNumbers.RecNum <= TableA.Quantity ORDER BY TableA.ID, tblNumbers.RecNum;

注意:tblNumbers.RecNum是一个长整数,以第1行= 1,第2行= 2等开头。

答案 5 :(得分:0)

这也可以解决问题。它使用递归,创建一个包含1-100行的表。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 111 &&   resultCode== Activity.RESULT_OK){
        val selectedfile=data?.data
val inputStream: InputStream = contentResolver!!.openInputStream(data!!.data!!)!!
        val inputString = inputStream.bufferedReader()
        inputString.readLine()
        inputString.readLine()
        inputString.readLine()
        inputString.readLine()
        inputString.readLine()
        val iterator = inputString.readLine().lineSequence().iterator()


        while (iterator.hasNext()) {

            val line = inputString.readLine()
            val lineV = "\\s+".toRegex()

            if (line != null) {

                var (nume, lat, lats, ns, long, longs, we) =                 line.split(lineV)

                val hashLat = HashMap<String, Float>()
                val  hashCard  =HashMap<String,String>()

                if (nume == "") {  nume = "wpnume" } else {    nume }

                //hashLat.put("nume", nume)
                hashLat.put("lat", lat.toFloat())
                hashLat.put("lats", lats.toFloat())
                hashCard.put("ns", ns)
                hashLat.put("lng", long.toFloat())
                hashLat.put("lngs", longs.toFloat())
                hashCard.put("we", we)
            println(hashLat)  //output something like:
            {lats=24.194, lat=57.0, lng=21.0, lngs=31.824}
            {lats=24.413, lat=57.0, lng=21.0, lngs=31.53}
            {lats=25.14, lat=57.0, lng=21.0, lngs=30.55}
           {lats=26.122, lat=57.0, lng=21.0, lngs=25.507}
           {lats=25.954, lat=57.0, lng=21.0, lngs=24.712}

答案 6 :(得分:0)

生成@n 行的一种非常简单的方法如下

DECLARE @n INT= 50

SELECT
    RowId   = ROW_NUMBER()OVER(ORDER BY (SELECT 0))
FROM
    (VALUES(CAST(REPLICATE('<a/>',@n) AS XML)))xmlLines(xmlLines)
    CROSS APPLY xmlLines.nodes('*')Lines(Line)

这个方法是有限制的。 由于 REPLICATE 函数生成最大长度为 8000 个字符的字符串, 生产线最多可达200​​0条。 要获得更大的数字,您可以使用以下方法:

DECLARE @n INT= 50;

WITH Block AS(
    SELECT
         RowId  = ROW_NUMBER()OVER(ORDER BY (SELECT 0))
        ,MaxBlockSize
    FROM
        (VALUES(128))MaxBlockSize(MaxBlockSize)
        CROSS APPLY (VALUES(CAST(REPLICATE('<a/>',CASE WHEN @n<MaxBlockSize THEN @n ELSE MaxBlockSize END) AS XML)))xmlLines(xmlLines)
        CROSS APPLY xmlLines.nodes('*')Lines(Line)
)
, Blocks AS(
    SELECT
         RowId          
        ,NextStart      = RowId*MaxBlockSize
    FROM
        Block
    WHERE
        RowId<=MaxBlockSize
    UNION ALL
    SELECT
         RowId          = Blocks.NextStart+Block.RowId          
        ,NextStart      = (Blocks.NextStart+Block.RowId)*MaxBlockSize
    FROM
        Blocks
        CROSS APPLY Block
    WHERE
        Blocks.NextStart+Block.RowId<=@n
)
SELECT RowId FROM Blocks ORDER BY RowId

MaxBlockSize 的取值选择为 128(理论上最大为 2000)已减少为 128 为查询效率的原因