从行值计算要加入的表名

时间:2015-03-08 06:10:34

标签: sql sqlite

我的表看起来有点像这样:

Table name: products

ID      PRODUCT_ID      TYPE       PRICE      ...
1       111             computer   xxx
2       222             book       xx
3       333             computer   xxxx

----------------------------------------------------------------

Table name: products_computer

ID      PRODUCT_ID      CPU     RAM      ....
1       111             amd     16
2       333             intel   8

----------------------------------------------------------------

Table name: products_book

ID      PRODUCT_ID      AUTHOR          YEAR_PUBLISHED        ....
1       222             Stephen King    xxxx

正如您所看到的,在表products中,每个产品都列有它们共有的列(如价格),其他表包含该产品类型的特定信息。

现在假设我们要列出按价格排序的每个类型的产品,并且还要在查询中包含products_*表的特定信息,而不是手动进行第二次查询以便检索信息。

虽然我几乎没有使用数据库和SQL,但是我的经验不足会遇到各种陷阱,试图连接字符串以构建products_*的{​​{1}}表名,或者创建一个映射{的{中间表' {1}}实际表名的值,我在后面的文档中发现它只是不起作用,试图将列/行值“绑定”为表名。

是否有任何“技巧”使这项工作(在1个查询中包含所有内容),或者我是否真的必须在我的代码中手动进行第二次查询?

3 个答案:

答案 0 :(得分:3)

如果我理解正确,那么您需要来自products表的所有列及其products_computerproducts_book表中的相应信息(如果有)。

如果是这个场景,那么我认为你需要的只是多个LEFT JOIN SQL语句

SQL语句

SELECT products.product_id, type , price, cpu, ram, author, year_published
FROM products
LEFT JOIN products_computer ON products.product_id = products_computer.product_id
LEFT JOIN products_book ON products.product_id = products_book.product_id
ORDER BY price

<强>输出

All products from products table and their corresponding informations

答案 1 :(得分:2)

使用UNION语句可以实现这一点。

SELECT 
    products.ID AS ID, products.PRODUCT_ID AS PRODUCT_ID, products.PRICE AS PRICE, products_computer.CPU AS CPU, products_computer.RAM AS RAM,
    null as AUTHOR, null as YEAR_PUBLISHED
  FROM products_computer
  JOIN products ON products_computer.PRODUCT_ID = products.PRODUCT_ID
UNION
SELECT 
    products.ID AS ID, products.PRODUCT_ID AS PRODUCT_ID, products.PRICE AS PRICE, null as CPU, null as RAM, 
    products_book.AUTHOR AS AUTHOR, products_book.YEAR_PUBLISHED AS YEAR_PUBLISHED 
  FROM products_book
  JOIN products ON products_book.PRODUCT_ID = products.PRODUCT_ID
ORDER BY PRICE  

两个单独的查询将合并为一个更大的查询。为此,每个SELECT语句中选择的列必须相同。请注意我为其他表中的列SELECT编辑空值的方式。

每个SELECT个人也会根据常见的PRODUCT_ID列加入products。价格包含在内,最后有ORDER BY语句按PRICE排序。

这是查询的输出:

Ordered Query Output

根据@ Zero的评论,可以将查询存储为视图。作为一次性操作,请将查询作为视图定义执行:

CREATE VIEW vw_products_all AS
       SELECT products.ID AS ID,
              products.PRODUCT_ID AS PRODUCT_ID,
              products.PRICE AS PRICE,
              products_computer.CPU AS CPU,
              products_computer.RAM AS RAM,
              NULL AS AUTHOR,
              NULL AS YEAR_PUBLISHED
         FROM products_computer
              JOIN products
                ON products_computer.PRODUCT_ID = products.PRODUCT_ID
       UNION
       SELECT products.ID AS ID,
              products.PRODUCT_ID AS PRODUCT_ID,
              products.PRICE AS PRICE,
              NULL AS CPU,
              NULL AS RAM,
              products_book.AUTHOR AS AUTHOR,
              products_book.YEAR_PUBLISHED AS YEAR_PUBLISHED
         FROM products_book
              JOIN products
                ON products_book.PRODUCT_ID = products.PRODUCT_ID
        ORDER BY PRICE;

...之后可以通过以下方式访问数据:

SELECT * FROM vw_products_all

......或更明确地(良好做法):

SELECT ID,
    PRODUCT_ID,
    PRICE,
    CPU,
    RAM,
    AUTHOR,
    YEAR_PUBLISHED
FROM vw_products_all

输出与原始查询的输出相同。

答案 2 :(得分:-1)

According to Larry Wall your instinct to be too lazy to write the code yourself is right。生成将所有这些表组合在一起的视图相当容易。试试这个:

DECLARE @SQL NVARCHAR(MAX) = 'CREATE VIEW vw_products_all AS ' +
    SUBSTRING((
        SELECT [text()] = REPLACE(REPLACE(REPLACE(
            ' UNION ALL {1}SELECT P.id, P.PRODUCT_ID, P.Name, {2} FROM dbo.products AS P INNER JOIN dbo.{0} AS PS ON P.PRODUCT_ID = PS.PRODUCT_ID'
            , '{0}', QUOTENAME(O.name))
            , '{1}', CHAR(10))
            , '{2}', SUBSTRING((
                SELECT [text()] = ', ' + ISNULL(QUOTENAME(C_this.name), 'NULL as ' + QUOTENAME(C_all.name))
                FROM sys.columns AS C_all
                    LEFT JOIN sys.columns AS C_this
                        ON O.object_id = C_this.object_id
                        AND C_all.name = C_this.name
                WHERE OBJECT_NAME(C_all.object_id) LIKE 'product[_]%'
                    AND c_all.name NOT IN ('PRODUCT_ID', 'ID')
                ORDER BY C_all.name
                FOR XML PATH('')
            ), 2, 10000000000000))
        FROM sys.objects AS O
        WHERE name LIKE 'product[_]%'
        FOR XML PATH('')
    ), 11, 1000000000000)

SELECT @SQL