MySQL:SELECT值WHERE子查询返回通配符值

时间:2011-11-22 19:21:01

标签: mysql wildcard

令人困惑的标题......我的道歉。

我得到的是一个包含两个相关行的表。我需要根据另一行中列的值来获取一行中的列值。

给出以下postmeta表:

+----------+------------+---------------------------------------------------+--------------------+
| meta_id  | post_id    | meta_key                                          |  meta_value        |
+----------+------------+---------------------------------------------------+--------------------+
| 6917     | 661        | member_categories_0_member_categories_name        | 11                 |
+----------+------------+---------------------------------------------------+--------------------+
| 6918     | 661        | member_categories_0_member_categories_description | First description  |
+----------+------------+---------------------------------------------------+--------------------+
| 6919     | 661        | member_categories_1_member_categories_name        | 12                 |
+----------+------------+---------------------------------------------------+--------------------+
| 6920     | 661        | member_categories_1_member_categories_description | Second description |
+----------+------------+---------------------------------------------------+--------------------+

我需要根据meta_value类别ID和post_id获取meta_value类别描述。例如,如果我的类别ID是11而我的post_id是661,我应该得到“第一个描述”。

我考虑使用子查询来获取与meta_value为'11'对应的meta_key,但我不知道如何根据'member_categories_x_member_categories_name'中的计数器找到描述。

不幸的是,我无法控制meta_key的名称。我得到了这个简单的查询,返回'member_categories_0_member_categories_name'。如何使用该值查找“第一个描述”?

    SELECT pm.meta_key 
    FROM postmeta pm
    WHERE pm.meta_value = "11"
    AND pm.post_id = 661

这是表格的SQL:

CREATE TABLE `postmeta` (
    `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    `post_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
    `meta_key` VARCHAR(255) NULL DEFAULT NULL,
    `meta_value` LONGTEXT NULL,
    PRIMARY KEY (`meta_id`),
    INDEX `post_id` (`post_id`),
    INDEX `meta_key` (`meta_key`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=30814;

INSERT INTO `postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES (6917, 661, 'member_categories_0_member_categories_name', '11');
INSERT INTO `postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES (6918, 661, 'member_categories_0_member_categories_description', 'First description');
INSERT INTO `postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES (6919, 661, 'member_categories_1_member_categories_name', '12');
INSERT INTO `postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES (6920, 661, 'member_categories_1_member_categories_description', 'Second description');

3 个答案:

答案 0 :(得分:1)

这很难看,但是那个表格远远没有标准化,任何没有扫描每一行的答案都会是这样的:

SELECT pm2.meta_value 
  FROM postmeta pm1
  JOIN postmeta pm2
    ON pm1.post_id = pm2.post_id
   AND SUBSTRING(pm1.meta_key,1,LENGTH(pm1.meta_key)-5) = SUBSTRING(pm2.meta_key,1,LENGTH(pm2.meta_key)-12)
   AND pm1.meta_key like '%_name'
   AND pm2.meta_key like '%_description'
 WHERE pm1.meta_value = 11
   AND pm1.post_id = 661

我们的想法是将表连接到自身,链接具有相同post_id的行,并且其meta_key是“相似的” - 它必须完全相同,除了一个以_name和一个结尾以_description结尾。

答案 1 :(得分:0)

这是原始的,但比从字符串中提取数字更快

SELECT pm2.meta_key,  pm2.meta_value 
FROM postmeta pm, postmeta pm2
WHERE pm.meta_value = "11"
AND pm.post_id = 661
and pm.meta_value = pm2.meta_value
AND pm.post_id = pm2.post_id
and substring(pm.meta_key,30) = substring(pm2.meta_key,30)

我道歉,我犯了一些错误,遵循了正确的错误:

SELECT pm2.meta_value 
FROM postmeta pm, postmeta pm2
WHERE pm.meta_value = "11" 
AND pm.post_id = 661
and pm.meta_id <> pm2.meta_id
AND pm.post_id = pm2.post_id
and substring(pm.meta_key,19,20) = substring(pm2.meta_key,19,20)

正如我所说的原始,但使用(恕我直言)来自数据库的CPU更少,并且更好地利用了索引。当然这对于20位数来说是安全的

当然如果你有超过2个meta_key(名称和描述),你应该添加:

AND pm2.meta_key like '%_description'
AND pm.meta_key like '%_name'

此索引无用(meta_key是详细说明):

INDEX `meta_key` (`meta_key`)

更好地添加这个:

INDEX `idx_post_id_meta_value` (`post_id`,`meta_value`)

答案 2 :(得分:0)

我不确定我是否完全理解你想要的东西。

这给出了完整的“表”,如果你想添加一个“where”子句,你可以在最后添加它,但为了获得最佳性能,请在子查询中添加。

select
  n.*, d.meta_value as meta_value_descrip
from 
  (
   select left(meta_key, 34) as xjoin, p.*
   from postmeta p where right(meta_key, 4)  = 'name'
  ) as n
left join   -- or inner join
  (
   select left(meta_key, 34) as xjoin, p.*
   from postmeta p where right(meta_key, 11) = 'description'
   ) as d
on n.post_id = d.post_id and n.xjoin = d.xjoin