代码之家  ›  专栏  ›  技术社区  ›  Mr. Smith

使用MySQL将值与表中的多个列(在一条语句中)匹配

  •  9
  • Mr. Smith  · 技术社区  · 15 年前

    我正在使用MySQL中包含以下列的表:

    id, january, february, march, april, etc
    

    表中的数据如下:

    aa, 0, 0, 1, 0
    ab, 1, 0, 1, 0
    ac, 1, 1, 0, 0
    ad, 1, 1, 1, 0
    

    要查询它,我可以很容易地做到:

    select * from table where january = 1 and february = 1
    

    结果是:

    ac, 1, 1, 0, 0
    ad, 1, 1, 1, 0
    

    我想知道是否有这样做的方法:

    select * from table where table.columns = 1
    

    我希望在表达式中使用表列,而不实际手动指定名称(键入它们)。

    奖金(+1)问题 :
    是否可以使用匹配/对像这样的:

    select * from table
    where
    (
        match (somehow,get,the,table,columns,I,need,here)
        against (1 in boolean mode)
    )
    

    谢谢你的时间!:)

    9 回复  |  直到 15 年前
        1
  •  4
  •   OMG Ponies    15 年前

    您必须使用准备好的语句,因为您要做的操作只能用动态SQL来完成:

    SET @stmt = 'SELECT * FROM YOUR_TABLE WHERE 1 = 1 '
    SET @stmt = CONCAT(@stmt, (SELECT CONCAT_WS(' AND ', CONCAT(column_name, ' = 1 '))
                                FROM INFORMATION_SCHEMA.COLUMNS
                               WHERE table_name = 'YOUR_TABLE'
                                 AND table_schema = 'db_name'
                                 AND column_name NOT IN ('id'))); 
    
    PREPARE stmt FROM @stmt;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    

    第一个set语句构造一个基本的select语句;“1=1”部分就在那里,以便更容易地连接 AND column = 1

    第二个set语句将查询的内容连接起来,以便根据表名将列列表获取到第一个set语句中字符串的末尾。其理念是:

    SELECT CONCAT_WS(' AND ', CONCAT(column_name, ' = 1 '))
      FROM INFORMATION_SCHEMA.COLUMNS
     WHERE table_name = 'YOUR_TABLE'
       AND table_schema = 'db_name'
       AND column_name NOT IN ('id')
    

    …将返回一行类似于“ AND january = 1 AND february = 1 ... “。如果在WHERE子句中还有其他不需要的列,则必须更新NOT IN子句。

    其余的只是标准的准备好的语句,这一切都必须在存储过程中进行。

        2
  •  1
  •   Jason246    15 年前

    我明白史密斯先生想做什么。

    这是一个12行x 4列与1行x 12列的问题。

    前一张桌子的设计如下:

    ID,某人的ID,月份,值x 12/月

    1, 101, january, 1
    2, 101, february, 1
    3, 101, march, 0
    etc..
    

    与此对应的SQL语句是:

    $sqlQuery = "SELECT month FROM my_month_table WHERE value = 1";
    

    我猜史密斯先生正在尝试:

    身份证,某人的身份证,一月,二月,三月…

    $sqlQuery = "SELECT corrensponding_column_names_to_where_clause FROM my_month_table WHERE column_value = 1";
    
        3
  •  1
  •   Sadat    15 年前

    你可以用Match…Against来做。

    在这种情况下,您的表必须是myisam表,并且必须创建包含必需列的全文索引。

        4
  •  1
  •   Lukasz Lysik    15 年前

    尝试创建视图

    CREATE VIEW v_months 
    AS 
    SELECT *, CONCAT( CAST(jan AS CHAR(1)), 
                      CAST(feb AS CHAR(1)),
                      CAST(mar AS CHAR(1)),
                      ...) AS all 
    FROM months
    

    你会得到这样的结果:

    aa, 0, 0, 1, 0, 0010
    ab, 1, 0, 1, 0, 1010
    ac, 1, 1, 0, 0, 1100
    ad, 1, 1, 1, 0, 1110
    

    然后你可以查询

    SELECT * FROM v_months WHERE all = '100110010101'
    

    或者,如果要查询“get all rows,where feb=1”,可以这样写:

    SELECT * FROM v_months WHERE all LIKE '_1____________'    
    

    其中“u”正好匹配一个字符。

        5
  •  0
  •   pingw33n    15 年前

    在mysql中可以使用向量:

    select * from table where (january, february) = (1, 1)
    

    注意文本列的不同服务器和客户机排序规则,那时可能需要显式指定排序规则。

        6
  •  0
  •   Jay    15 年前

    在我看来,这是由看起来不好的表设计造成的(我猜这只是简单地说明你的问题的一个例子,但请接受我的看法,我认为这个概念可以更好地建模。
    以下是表格:

      Things        Things_Months      Months
       thing_id       thing_id           Month_id
       thing_info     month_id           Month_Name
                      thing_month_id     order_field
    

    下面是SQL:

     select thing_info, month_name
      from things, things_months, months
      where things.thing_id = things_months.thing_id
        and things_months.month_id = months.month_id 
      order by things.things_info, months.order_field
    

    结果是

      thingy 1, January
      thingy 1, February
      thingy 2, April
      thingy 3, November
      thingy 3, December
    
        7
  •  0
  •   longneck    15 年前
    select * from table where 1 in (january, february)
    
        8
  •  0
  •   Blama    15 年前

    用视图解决问题怎么样?

    CREATE TABLE `d001ab05`.`months` (
    `id` INT NOT NULL ,
    `jan` BOOL NOT NULL ,
    `feb` BOOL NOT NULL ,
    `mar` BOOL NOT NULL ,
    `apr` BOOL NOT NULL ,
    `may` BOOL NOT NULL ,
    `jun` BOOL NOT NULL ,
    `jul` BOOL NOT NULL ,
    `aug` BOOL NOT NULL ,
    `sep` BOOL NOT NULL ,
    `oct` BOOL NOT NULL ,
    `nov` BOOL NOT NULL ,
    `dec` BOOL NOT NULL ,
    PRIMARY KEY ( `id` )
    ) ENGINE = InnoDB;
    

    插入数据:

    INSERT INTO `d001ab05`.`months` (
    `id`, `jan`, `feb`, `mar`, `apr`, `may`, `jun`,
    `jul`, `aug`, `sep`, `oct`, `nov`, `dec`
    ) VALUES (
    '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
    ), (
    '2', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
    ), (
    '3', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
    ), (
    '4', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'
    );
    

    选择查看:

    CREATE OR REPLACE VIEW `moncase` AS
    SELECT id,
    CASE WHEN `jan` =1 OR `feb` =1 OR `mar` =1 OR `apr` =1 OR `may` =1 OR
    `jun` =1 OR `jul` =1 OR `aug` =1 OR `sep` =1 OR `oct` =1 OR `nov` =1 OR `dec` =1
    THEN 1 ELSE 0 END AS or_over_months
    FROM months;
    

    选择:

    SELECT * FROM `moncase` WHERE `or_over_months` = 1;
    

    结果:

    id | or_over_months
    1  | 1
    2  | 1
    4  | 1
    
        9
  •  0
  •   Bill Karwin    15 年前

    你需要的是一个联合国支点行动。Microsoft SQL Server支持 PIVOT UNPIVOT 作为标准SQL的扩展。我不知道还有其他品牌的RDBMS支持内置的Pivot/UnPivot功能。当然,MySQL不支持这一点。

    你不能用 FULLTEXT 在这种情况下搜索,因为作为文档 say :

    全文索引只能用于myisam表,并且只能为char、varchar或text列创建。

    它不会解除您无论如何都需要指定列的义务,因为 MATCH() 谓词需要您列出 全部的 全文索引中的列。

    如果无法重新构造表以每月存储一行,或者无法对单个列进行全部12个月的编码,则需要生成动态SQL。