【问题标题】:How to select true/false based on column value?如何根据列值选择真/假?
【发布时间】:2010-03-07 16:04:59
【问题描述】:

我有一个包含以下列的表格: EntityId, EntityName, EntityProfile, ....................

我想根据实体配置文件的值选择 Id 和 Name 以及 true/false 列, 例如,返回的结果集如下所示,表示实体 1 和 2 有配置文件,而 3 没有。

1 Name1 True
2 Name2 True
3 Name3 False
etc.....

我知道我可以使用一个基于配置文件值返回真/假的函数来做到这一点,如下所示: SELECT EntityId, EntityName, dbo.EntityHasProfile(EntityId) AS HasProfile FROM Entities

但我要返回一个很大的号码。记录的数量和对每条记录的此函数调用,查询非常慢,当我删除函数调用时,查询执行时间显着下降。

那么还有其他方法吗? 谢谢

【问题讨论】:

  • 您可能可以join,但您没有告诉我们EntityHasProfile 是如何计算的。你还有另一张桌子吗?
  • 对不起,我忘了提,实体配置文件是 nvarchar(max)
  • 以及如何使用EntityProfile来判断是否有EntityHasProfile?如果它为空...?
  • 是的,如果为空,我想得到假,否则为真

标签: sql-server


【解决方案1】:

使用CASE。我会发布特定代码,但需要比帖子中提供的更多信息 - 例如 EntityProfile 的数据类型以及通常存储在其中的内容。比如:

CASE WHEN EntityProfile IS NULL THEN 'False' ELSE 'True' END

编辑 - 整个 SELECT 语句,根据 cmets 中的信息:

SELECT EntityID, EntityName, 
       CASE WHEN EntityProfile IS NULL THEN 'False' ELSE 'True' END AS HasProfile
FROM Entity

在这种情况下不需要 LEFT JOIN...

【讨论】:

  • 如果我有 20 列及以上的列具有位(真/假)数据类型怎么办?可以同样应用@froadie
  • 为了扩展这个答案,这会返回 True 或 False。它完全满足 OP,但作为实际的位 T/F 字段可能更有用(如 Kopika 所述)。我会使用这个案例语句:SELECT EntityID, EntityName, cast(CASE WHEN EntityProfile IS NULL THEN 0 ELSE 1 END) as bit) AS HasProfile FROM Entity
  • @Rob 谢谢你。但是括号打开一次,关闭两次?
【解决方案2】:

你可以试试

SELECT  e.EntityId, 
        e.EntityName, 
        CASE 
            WHEN ep.EntityId IS NULL THEN 'False' 
            ELSE 'TRUE' 
        END AS HasProfile 
FROM    Entities e LEFT JOIN 
        EntityProfiles ep ON e.EntityID = ep.EntityID

或者

SELECT e.EntityId, 
        e.EntityName, 
        CASE 
            WHEN e.EntityProfile IS NULL THEN 'False' 
            ELSE 'TRUE' 
        END AS HasProfile 

FROM    Entities e

【讨论】:

    【解决方案3】:

    如果您确定实体是否具有配置文件的方式是确定性函数,并且不需要访问另一个表,您可以编写一个存储函数并定义一个计算的持久字段来存储该值为您服务,而不必一遍又一遍地重新计算。

    如果您需要查询一个单独的表(例如检查一行是否存在),您仍然可以将此“HasProfile”作为实体表中的一列,并定期计算该字段,例如每天晚上左右。如果您将值存储为原子值,则不需要每次都进行计算。只要该事实(无论是否有个人资料)变化不会太频繁,这种方法就有效。

    要添加一列来检查EntityProfile 是否为空,请执行以下操作:

    CREATE FUNCTION CheckHasProfile(@Field VARCHAR(MAX))
    RETURNS BIT
    WITH SCHEMABINDING
    AS BEGIN
        DECLARE @Result BIT
    
        IF @Field IS NULL OR LEN(@Field) <= 0
            SET @Result = 0
        ELSE
            SET @Result = 1
    
        RETURN @Result
    END
    

    然后在你的表中添加一个新的计算列Entity

    ALTER TABLE dbo.Entity
       ADD HasProfile AS dbo.CheckHasProfile(EntityProfile) PERSISTED
    

    现在你有一个 BIT 列并且它被持久化了,例如每次访问该行时都不会计算,应该执行得很好!

    【讨论】:

      【解决方案4】:

      也许为时已晚,但我会将 0/1 转换为位,以使数据类型在 .NET 框架使用时最终变为 True/False:

      SELECT   EntityId, 
               EntityName, 
               CASE 
                  WHEN EntityProfileIs IS NULL 
                  THEN CAST(0 as bit) 
                  ELSE CAST(1 as bit) END AS HasProfile
      FROM      Entities
      LEFT JOIN EntityProfiles ON EntityProfiles.EntityId = Entities.EntityId`
      

      【讨论】:

      • 那为什么不直接像boolean呢? CASE WHEN EntityProfileIs IS NULL THEN false ELSE true END AS HasProfile
      • @adrenalin SqlServer 中没有 boolean 数据类型。我们使用BIT 数据类型来表示布尔数据。 BIT 字段的值可以是 10 或 *null(*如果允许)。
      【解决方案5】:

      至少在 Postgres 中你可以使用以下语句:

      SELECT EntityID, EntityName, EntityProfile IS NOT NULL AS HasProfile FROM Entity
      

      【讨论】:

        【解决方案6】:

        UDF EntityHasProfile() 有什么作用?

        通常你可以用 LEFT JOIN 来做这样的事情:

        SELECT EntityId, EntityName, CASE WHEN EntityProfileIs IS NULL THEN 0 ELSE 1 END AS Has Profile
        FROM Entities
        LEFT JOIN EntityProfiles
            ON EntityProfiles.EntityId = Entities.EntityId
        

        这应该消除对昂贵的标量 UDF 调用的需要 - 根据我的经验,标量 UDF 应该是 SQL Server 中大多数数据库设计问题的最后手段 - 它们根本不是表现良好的。

        【讨论】:

        • udf 应该测试传递的 id 的实体配置文件的值,如果 null 返回 false,否则返回 true
        猜你喜欢
        • 2013-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-10
        • 1970-01-01
        相关资源
        最近更新 更多