代码之家  ›  专栏  ›  技术社区  ›  Jake Miller

仅在满足某些条件时尝试强制转换列

  •  3
  • Jake Miller  · 技术社区  · 7 年前

    我的公司使用媒体管理软件,将媒体的所有元数据存储在一个表中(维度、标题、标题、标记等)。因此,所有值都是 VARCHAR 是的。这不是什么大问题,因为每一行都有一个名为 MetaName 它定义了该行中存在的数据类型。例如,元名称1是标题字段,元名称3是高度(以像素为单位)。

    我正试图找到特定维度之间的像素图像。因为这些值存储为类型 瓦查尔 例如 1200px ,我需要替换 px 投给一个 INT 在我测试这样的尺寸范围之前: CAST(REPLACE(VALUE, 'px', '') AS INT) 是的。

    下面是一个简化的模式和一个示例,可以更容易地理解我所说的内容:

    CREATE TABLE Media (
      ID INT IDENTITY(1,1) PRIMARY KEY,
      ImagePath VARCHAR(MAX)
    );
    
    CREATE TABLE MetaData (
      ID INT IDENTITY(1,1) PRIMARY KEY,
      MediaId INT REFERENCES Media(ID),
      MetaName INT NOT NULL,
      Value VARCHAR(MAX) NOT NULL DEFAULT ''
    );
    

    测试值+我的查询:

    INSERT INTO Media (ImagePath)
    VALUES
    ('C:/mypath/myimage.png'), 
    ('C:/mypath/otherimage.jpg');
    
    INSERT INTO MetaData (MediaId, MetaName, Value)
    VALUES 
    (1, 1, 'Title1'), (2, 1, 'Title2'),
    (1, 2, 'Description1'), (2, 2, 'Description2'),
    (1, 3, '1260px'), (2, 3, '1100px'),
    (1, 4, '800px'), (2, 4, '1900px');
    
    SELECT * FROM MetaData
    WHERE 
     (MetaName = 3 AND CAST(REPLACE(Value, 'px', '') AS INT) BETWEEN 800 AND 1200)
     OR
     (MetaName = 4 AND CAST(REPLACE(Value, 'px', '') AS INT) BETWEEN 800 AND 1200)
    

    不过,这应该行得通, CAST 调用失败,因为查询尝试强制转换所有值列,因此当查询运行到“title1”或“description1”时,将发生错误。

    如何仅在metaname=3或4的字段上强制转换?我想 MetaName = 3 以及 MetaName = 4 在条件语句的开头 AND 会阻止 铸造 + REPLACE 但它会在所有列上发生。

    3 回复  |  直到 7 年前
        1
  •  3
  •   S3S    7 年前

    您可以在SQL Server 2012以后的版本上使用try_convert

    SELECT * FROM MetaData
    WHERE 
     (MetaName = 3 AND try_convert(int,REPLACE(Value, 'px', '')) BETWEEN 800 AND 1200)
     OR
     (MetaName = 4 AND try_convert(int,REPLACE(Value, 'px', '')) BETWEEN 800 AND 1200)
    

    或者试试看

    SELECT * FROM MetaData
    WHERE 
     (MetaName = 3 AND try_cast(REPLACE(Value, 'px', '') as int) BETWEEN 800 AND 1200)
     OR
     (MetaName = 4 AND try_cast(REPLACE(Value, 'px', '') as int) BETWEEN 800 AND 1200)
    

    或者,你可以用 CASE

    SELECT * FROM MetaData
    where
    (MetaName = 3 AND case when MetaName = 3 then CAST(REPLACE(Value, 'px', '') AS INT) end BETWEEN 800 AND 1200)
     OR
    (MetaName = 4 AND case when MetaName = 4 then CAST(REPLACE(Value, 'px', '') AS INT) end BETWEEN 800 AND 1200)
    

    或者,使用 IIF

    SELECT * FROM MetaData
    where
    (MetaName = 3 AND iif(MetaName = 3,CAST(REPLACE(Value, 'px', '') AS INT),null) BETWEEN 800 AND 1200)
     OR
    (MetaName = 4 AND iif(MetaName = 4,CAST(REPLACE(Value, 'px', '') AS INT),null) BETWEEN 800 AND 1200)
    

    或者,使用 CTE 是的。

    ;with cte as(
    SELECT * FROM MetaData
    where MetaName in (3,4))
    
    select *
    from cte
    where CAST(REPLACE(Value, 'px', '') AS INT) BETWEEN 800 AND 1200
    
        2
  •  2
  •   NikhilC    7 年前

    你能做的是用try_cast代替cast。

    SELECT * FROM MetaData
    WHERE 
     (MetaName = 3 AND TRY_CAST(REPLACE(Value, 'px', '') AS INT) BETWEEN 800 AND 1200)
     OR
     (MetaName = 4 AND TRY_CAST(REPLACE(Value, 'px', '') AS INT) BETWEEN 800 AND 1200)
    

    当我这样做时,它只返回作为结果集一部分的元名称3和4。我相信此功能是在SQL Server 2012中引入的。

        3
  •  2
  •   kiran gadhe    7 年前
     SELECT * FROM MetaData
     WHERE 
     ( case when (MetaName = 3 or MetaName = 4)  then  CAST(REPLACE(Value, 'px', '') AS INT) else NULL end )  
      BETWEEN 800 AND 1200