0

我已经阅读了许多类似问题的帖子,但还没有找到答案。我对 SQL 很陌生。使用 SQL Server Express 2008。

我的目标是获得在具有相似名称的几个列中不同的所有值的单列结果。相关列具有相同的基本名称(后缀),后跟一个整数。我有很多列组,所以我不想对查询进行硬编码。

Fruit1 Coating1 Temperature1   Fruit2 Coating2  Temperature2 Fruit3 Coating3  Temperature3
-----------------------------------------------------------------------------------
apple  caramel  72.5           pear   chocolate  74.1        apple  chocolate  98.6
pear   caramel  73.3           peach  chocolate  42.7        apple  chocolate  33.0

所以我希望服务器返回,例如,任何/所有水果列中使用的所有水果 apple peach pear

我已经知道如何使用通配符获取列名列表:

SELECT Column_name AS columnNames
FROM INFORMATION_SCHEMA.COLUMNS
WHERE Column_name LIKE 'Fruit%' 

如果我已经知道列名,我也知道如何从列中找到不同的值:

SELECT DISTINCT Fruit FROM(
SELECT Fruit1 as Fruit from FruitBasket
UNION
SELECT Fruit2 as Fruit from FruitBasket
UNION
SELECT Fruit3 as Fruit from FruitBasket)
AS finalOutput

我需要知道的是如何在第二个的 UNION 参数中使用第一个查询的列名结果。我应该使用 FOR 循环还是什么?

谢谢!

4

3 回答 3

0

我同意应该改进数据库设计,但是如果你接到一个巨大的项目并且现在需要数据,你可以用游标/动态 sql/临时表做一些疯狂的事情:

GO

DECLARE @sql varchar(500) = '',
        @currentColumn varchar(50)


CREATE TABLE #fruit (Fruit varchar(20))

DECLARE fruit_cursor CURSOR FOR
    SELECT c.name
    FROM sys.tables t
        INNER JOIN sys.columns c
            on t.object_id = c.object_id
    WHERE t.name = 'TABLE NAME HERE'
    AND c.name like 'Fruit%'

OPEN fruit_cursor

FETCH NEXT FROM fruit_cursor INTO @currentColumn

WHILE @@FETCH_STATUS = 0 BEGIN

    SET @sql = 
        'INSERT INTO #fruit ' +
        'SELECT @columnName ' +
        'FROM TABLE NAME HERE'

    SET @sql = REPLACE(@sql, '@columnName', @currentColumn)

    EXEC(@sql)

    FETCH NEXT FROM fruit_cursor INTO @currentColumn
END

CLOSE fruit_cursor

DEALLOCATE fruit_cursor

SELECT DISTINCT Fruit  
FROM #fruit
ORDER BY Fruit

DROP TABLE #fruit 

不过,对于未来,我强烈建议研究多对多关系。

于 2013-04-30T19:40:56.523 回答
0

感谢大家的建议。

首先,根据我收到的回复,我为我的原始问题创建了一个丑陋但有效的解决方案。它基本上执行一个查询字符串,该查询字符串由另一个同名列的查询组合而成。实际上,输出是来自多个具有相似名称的列的所有不同值的列表。这段代码粘贴在下面。

但是,正如你们所说,整个架构很糟糕。如果我尝试对这些结果做任何有用的事情,它会变得非常复杂,因为我需要跟踪不同值所属的列号。尝试对相应编号的列中的数据进行排序或比较更加疯狂,因为我无法确定苹果是否总是放在“Fruit1”中,而桃子是否总是放在“Fruit2”中,或者相反,等等。

睡在上面之后,我想出了一个更好的解决方案,即创建另一个单一的所有“水果篮”数据表,这些数据(虽然可能不是“多对多”)与“事件”双向链接历史”行到“水果篮”表中的一行,因此我可以轻松地在所有水果篮中搜索特定信息,然后点击链接返回事件历史记录。这样,如果我发现苹果在 398.2 度以上有毒,我可以很容易地找到所有发送如此热的苹果的事件,或者我可以按温度对所有带有苹果的事件进行排序。

这将需要在我的应用程序代码中进行一些重写,但最好现在修复它。:-)

这是我在名称相似的列中查找不同值的代码,但如上所述,我毕竟不会在我的项目中使用它。

DECLARE @sql varchar(MAX) = 'SELECT DISTINCT FriutBasketInfo FROM(',
    @currentColumn varchar(50)

DECLARE fruit_cursor CURSOR FOR    
    SELECT Column_name AS columnNames
    FROM INFORMATION_SCHEMA.COLUMNS
    --WHERE Column_name LIKE 'Fruit%' 
    --WHERE Column_name LIKE 'Coating%' 
    WHERE Column_name LIKE 'Temperature%'    

OPEN fruit_cursor

FETCH NEXT FROM fruit_cursor INTO @currentColumn
SET @sql = @sql + 'SELECT ' + @currentColumn + ' as FriutBasketInfo from FruitBasketHistoryTable '
FETCH NEXT FROM fruit_cursor INTO @currentColumn

WHILE @@FETCH_STATUS = 0 BEGIN    
    SET @sql = @sql + ' UNION SELECT ' + @currentColumn + ' as FriutBasketInfo from FruitBasketHistoryTable '
    FETCH NEXT FROM fruit_cursor INTO @currentColumn    
END

SET @sql = @sql + ') AS finalOutput'

EXEC(@sql)

CLOSE fruit_cursor
DEALLOCATE fruit_cursor
于 2013-05-01T14:51:42.397 回答
0

编辑:

用户在评论中提到他愿意接受新设计。

单击此处查看以下代码的工作示例

我同意这是一个糟糕的设计。我不知道如何使它变得更好。

以下是改进设计的方法:

    CREATE TABLE fruit
(
  fruit_id INT CONSTRAINT pk_fruit_pid PRIMARY KEY,
  fruit_name VARCHAR(25)
);

CREATE TABLE temperature
(
  temperature_id INT CONSTRAINT pk_sprinkle_pid PRIMARY KEY,
  temperature_value DECIMAL(18,1)
);

CREATE TABLE coating
(
  coating_id INT CONSTRAINT pk_coating_pid PRIMARY KEY,
  coating_name VARCHAR(25)
);

CREATE TABLE fruit_temperature_coating
(
  fruit_id INT CONSTRAINT fk_fruit_fid FOREIGN KEY REFERENCES fruit(fruit_id),
  temperature_id INT CONSTRAINT fk_temp_fid FOREIGN KEY REFERENCES temperature(temperature_id),
  coating_id INT CONSTRAINT fk_coating_fid FOREIGN KEY REFERENCES coating(coating_id)
);

运行查询:

     SELECT f.fruit_name, 
       t.temperature_value, 
       c.coating_name 
FROM   fruit_temperature_coating AS fpc
       INNER JOIN Fruit AS f 
               ON fpc.fruit_id = f.fruit_id 
       INNER JOIN temperature AS t
               ON fpc.temperature_id = t.temperature_id 
       INNER JOIN coating AS c 
               ON fpc.coating_id = c.coating_id 
于 2013-04-30T19:15:56.797 回答