如何从具有相似名称的列中查找DISTINCT值

时间:2013-04-30 19:03:43

标签: sql sql-server-2008-express distinct-values

我读了许多类似问题的帖子,但还没有找到答案。我对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

所以我希望服务器返回,例如,任何/所有水果列中使用的所有水果     苹果     桃子     梨

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

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循环还是什么?

谢谢!

3 个答案:

答案 0 :(得分:0)

编辑:

用户在评论中提到他对新设计持开放态度。

Click here for a working example of the below code

  

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

以下是改进设计的方法:

    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 

答案 1 :(得分:0)

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

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 

但是,对于未来,我强烈建议调查多对多关系。

答案 2 :(得分:0)

感谢大家的建议。

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

然而,正如你们所说,整个架构都很糟糕。如果我尝试对这些结果做任何有用的事情,它会变得非常复杂,因为我需要跟踪哪个列号属于一个不同的值。尝试对相应编号的列中的数据进行排序或比较更加疯狂,因为我不能确定苹果是否总是放在“Fruit1”中,Peaches放在“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