【问题标题】:how to use result of function as column name in where clause sql如何在where子句sql中使用函数的结果作为列名
【发布时间】:2018-04-04 10:50:18
【问题描述】:

这样的表结构

select * from TimeTable;

        userid | 1am|2am|3am| 4am| 5am
        1002   | 1  |1  |1  | 1  | 1
        1003   | 1  |1  |1  | 1  | 1 
        1004   | 1  |1  |1  | 1  | 1
        1005   | 1  |1  |1  | 1  | 1

我想要选择具有特定时间列的列值为 1 的用户 我使用了以下查询,但它抛出错误

com.microsoft.sqlserver.jdbc.SQLServerException:转换失败 将 varchar 值 '[3PM]' 转换为数据类型 int 时。

select * from UserDetail u,TimeTable t  
where u.userid=t.userid
and CONCAT(SUBSTRING(CONVERT(VARCHAR, getdate(), 100), 13, 2) ,'',RIGHT(CONVERT(VARCHAR, GETDATE(), 100),2)) = 1

像这样 当我使用硬编码的列名时,它工作正常 我想动态选择一个列名。

select * from UserDetail u,TimeTable t  
where u.userid = t.userid
and [3AM] = 1

【问题讨论】:

  • 今日提示:切换到现代显式 JOIN 语法。更容易编写(没有错误),更容易阅读(和维护),并且在需要时更容易转换为外连接。
  • 您确定您使用的是 MySQL 吗?这看起来像 SQL Server 语法。
  • 那个 CONCAT 条件没有比较。
  • 您不能将子查询的结果用作 SQL 中的列名 ..(您应该为此使用动态 sql)..
  • 您可以为子查询的结果分配一个列名,但不能在同一个 select 语句的 where 子句中引用它,除非您在那里重复相同的子查询。我将源查询设计为 VIEW,这样我就可以引用子查询结果列,就像我在使用视图的查询中使用表列一样。目前您的帖子中根本没有子查询,所以请先澄清一下。

标签: sql-server


【解决方案1】:

选项 1

使用如下一长串短路的 WHERE 子句,考虑到表格设计,这似乎很好,而且很容易理解

DECLARE @currentHour int = DATEPART(HOUR, getdate())
SELECT * FROM TimeTable
WHERE
    (@currentHour = 1 AND [1am] = 1) OR
    (@currentHour = 2 AND [2am] = 1) OR
    (@currentHour = 3 AND [3am] = 1) OR
    (@currentHour = 4 AND [4am] = 1) OR
    (@currentHour = 5 AND [5am] = 1) -- Etc

选项 2

使用 UNPIVOT 或 VALUES 将基于小时的列旋转为行。作为轮换的一部分,您可以将列转换为表示小时的数字。您可以将其与当前时间的小时部分进行比较。

选项 3

使用动态 sql,它可能适合您的环境或用途,也可能不适合。

下面是 UNPIVOT 方法(选项 2),理解起来有点复杂。

create table Test (id int, [1am] int, [2am] int, [3am] int, [4am] int)

insert Test values
  (1, 1, 2, 3, 4)
  , (2, 11, 12, 13, 14)
  , (3, 1, 21, 23, 24)
  , (4, 31, 32, 33, 34)

declare @time datetime = '2018-01-01 01:10:00' -- change this to getdate()

;WITH MatchingIds (id) AS
(
  SELECT id
  FROM
    (SELECT 
       id,  
       [1am] AS [1], [2am] AS [2], [3am] AS [3], [4am] AS [4] --etc 
     FROM Test) AS Source
     UNPIVOT
     (val FOR hour IN 
      ([1], [2], [3], [4]) --etc
     ) AS asRows
  WHERE 
      hour = CONVERT(VARCHAR, DATEPART(HOUR, @time)) 
      AND val = 1
) 
SELECT * FROM MatchingIds
-- MatchingIds now contains the rows that match your criteris
-- This can be joined with other tables to generate your full result

上述示例的 MatchingIds 的中间输出,时间参数设置为凌晨 1 点左右

| id |
|----|
|  1 |
|  3 |

http://sqlfiddle.com/#!18/85c9c/5

【讨论】:

  • 谢谢,这将帮助我找到解决方案!
【解决方案2】:

试试:

select * from UserDetail u,TimeTable t  
where u.userid=t.userid
and 
(select COLUMN_NAME 
 from INFORMATION_SCHEMA.COLUMNS 
 where    TABLE_NAME = 'tblName' 
      AND TABLE_CATALOG = 'DBNAME'
      AND COLUMN_NAME = CONCAT(SUBSTRING(CONVERT(VARCHAR, getdate(), 100), 13, 2) ,'',RIGHT(CONVERT(VARCHAR, GETDATE(), 100),2))) = 1

【讨论】:

    【解决方案3】:

    select CONCAT(SUBSTRING(CONVERT(VARCHAR, getdate(), 100), 13, 2) ,'',RIGHT(CONVERT(VARCHAR, GETDATE(), 100),2))varchar 类型的值,而不是查询的语法。您目前正在做的是类似于 sql:

    select * from UserDetail u,TimeTable t  
    where u.userid=t.userid
    and '12PM' = 1
    

    即使解析器接受了您的查询,条件也始终为 false,因为 '12PM'12PM[12PM] 不同。您不能在查询本身中动态修改查询以使其正常工作。

    是的,您可以使用动态执行等技巧(将整个查询构建为字符串,然后执行它),但请不要这样做。您的代码中真正的问题是您的表格设计相当糟糕。考虑重新设计您的 TimeTable 表以将 timeOfDay 值设置为单个列,并将实际时间值作为该列中的数据。以后你会省去很多麻烦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-10
      • 2018-05-07
      • 2011-03-12
      • 1970-01-01
      • 2018-02-17
      • 1970-01-01
      • 1970-01-01
      • 2018-05-17
      相关资源
      最近更新 更多