将来自2个表的数据合并到1个动态查询中

时间:2011-11-16 12:20:42

标签: sql sql-server-2005 dynamicquery

我有两张桌子:

table 1
id    item     itemType 
-----------------------
1     book1    1
2     book2    1
3     laptop1  2

table 2
id    itemId    name    value
------------------------------------------
1     1         author  enid blyton
2     1         title   five 1
3     2         author  enid blyton
4     2         title   five 2
5     3         cpu     i7-940
6     3         ram     4 GB
7     3         vcard   nvidia quadro

当我使用过滤器itemType = 1查询时,结果应为:

query 1
id    item    author          title
--------------------------------------------------------
1     book1   enid blyton     five 1
2     book2   enid blyton     five 2

并使用过滤器itemType = 2

query 2
id    item       cpu       ram        vcard
----------------------------------------------
1     laptop1    i7-940    4 GB       nvidia quadro

且没有过滤器

query 3
id    item    author          title      cpu       ram         vcard
---------------------------------------------------------------------------
1     book1   enid blyton     five 1
2     book2   enid blyton     five 2
1     laptop1                            i7-940    4 GB        nvidia quadro

我使用表2的原因是因为每个itemType的参数都是在飞行期间创建的,因此不可能有像查询3中那样的表。

此时我可以通过以编程方式重建表(使用大量的linq调用)来解决这个问题。表1(1K行)和2(10K行)的小尺寸,性能良好,但现在表1的大小已超过100K行,表2超过1M行,性能非常好低。

是否有任何使用SQL查询的函数可以解决这个问题?

2 个答案:

答案 0 :(得分:1)

不完全是动态的,但如果您的名字都是预先知道的,则可以使用PIVOT来检索您的数据。

  

PIVOT通过转动唯一值来旋转表值表达式   从表达式中的一列到输出中的多个列,   并在任何剩余的情况下执行聚合   最终输出中需要的列值。

SQL语句

SELECT  t1.Id
        , t1.item
        , t2.author
        , t2.title
        , t2.cpu
        , t2.ram
        , t2.vcard
FROM    table1 t1
        INNER JOIN (        
          SELECT  *
          FROM    (
                    SELECT  itemId
                            , name
                            , value 
                    FROM    table2
                  ) s
                  PIVOT (
                    MAX(Value) 
                    FOR name IN (title, author, cpu, ram, vcard)
                  ) p
        ) t2 ON t2.itemId = t1.Id

测试脚本

;WITH table1 (id, item, itemtype) AS (
    SELECT 1, 'book1', 1
    UNION ALL SELECT 2, 'book2', 1
    UNION ALL SELECT 3, 'laptop1', 2
)
, table2 (id, itemId, name, value) AS (
    SELECT 1, 1, 'author', 'enid blyton'
    UNION ALL SELECT 2, 1, 'title', 'five 1'
    UNION ALL SELECT 3, 2, 'author', 'enid blyton'
    UNION ALL SELECT 4, 2, 'title', 'five 2'
    UNION ALL SELECT 5, 3, 'cpu', 'i7 940'
    UNION ALL SELECT 6, 3, 'ram', '4 GB'
    UNION ALL SELECT 7, 3, 'vcard', 'nvidia quadro'
)
SELECT  t1.Id
        , t1.item
        , t2.author
        , t2.title
        , t2.cpu
        , t2.ram
        , t2.vcard
FROM    table1 t1
        INNER JOIN (        
          SELECT  *
          FROM    (
                    SELECT  itemId
                            , name
                            , value 
                    FROM    table2
                  ) s
                  PIVOT (
                    MAX(Value) 
                    FOR name IN (title, author, cpu, ram, vcard)
                  ) p
        ) t2 ON t2.itemId = t1.Id

答案 1 :(得分:1)

我建议运行一个查询,从table2返回指定itemtype的所有可能名称,如下所示:

select distinct name
from table2 t2
where exists (select null
              from table1 t1
              where t1.itemtype = @itemtype and
                    t1.id = t2.item_id)

在C#中,将名称连接成一个以逗号分隔的字符串,然后构造一个类似于Lieven答案的新查询字符串,如下所示:

SELECT  t1.item
        , t2.*
FROM    table1 t1
        INNER JOIN (SELECT  *
                    FROM    (SELECT  itemId,
                                     name,
                                     value 
                             FROM    table2) s
                            PIVOT (MAX(Value) 
                                   FOR name IN (/*insert names string here*/)) p
                   ) t2 ON t2.itemId = t1.Id
WHERE t1.itemtype = @itemtype;

(使用名称字符串替换括号内的注释)。

顺便说一下,如果可能的话,我建议将表2中的名称分成单独的查找表,如下所示:

name_table
----------
name_id
name
itemtype

- 这意味着第一个查询只需要查询一个小的查找表而不是查询表2;它也可以用于数据输入时名称值的一致性。