MySQL查询非空值,其中key是字符串的一部分

时间:2011-11-15 19:38:54

标签: mysql

我的数据库设置如下(简化):

+----------+---------+----------+
|   path   |  val1   |   val2   |
+----------+---------+----------+
|    a/    |   two   |   cow    |
+----------+---------+----------+
|   a/b/   |   one   |   cat    |
+----------+---------+----------+
|  a/b/c   |   NULL  |   bat    |
+----------+---------+----------+

路径是主键(在实际使用中,更像是Smith / John / Mark / Jr)。

PHP提供路径$mypath = "a/b/c";

是否有一种方法可以构建非空值的结果集,从path属于$ mypath的所有行中进行选择。
也就是说,要搜索最匹配的键,找到其中的所有非空值,如果有任何空值,则从第二个“最佳”键中获取它们。

EG。 Mysql应检查a / b / c并返回val2 =“bat”,但是看到val1设置为NULL。
因此应该检查a / b /并设置val1 =“one”;
最终结果应为array('val1' => "one", 'val2' => "bat")

一位朋友告诉我,有一种“LOCATE”方式,但我无法解决这个问题 这可行吗?

知道MySQL的人可以帮我改写这个问题的标题更具描述性吗?

感谢。

3 个答案:

答案 0 :(得分:1)

路径的过滤器是否从左到右严格比较,没有中间匹配?看来情况确实如此,但我想确定一下。

另外,我不确定你的逻辑基础/规则是什么,以确定应该选择III,但是这里有一个例子,如果val2是一个数字列,那将会起作用:

CREATE PROCEDURE `test`(IN phpPath VARCHAR(50))
BEGIN

SELECT A.val1, B.val2
FROM 
 (SELECT val1 FROM `yourtablehere` 
 WHERE val1 IS NOT NULL AND instr(phpPath, path) = 1 
 ORDER BY length(path) DESC) A
 , (SELECT val2 FROM `yourtablehere` 
 WHERE val2 IS NOT NULL AND instr(phpPath, path) = 1 
 ORDER BY length(path) DESC) B
LIMIT 1

END

你能测试一下,如果你得到了理想的结果,请告诉我们吗? (同样,首先假设列val2是数字)

我还建议您在代码中使用存储过程而不是嵌入式SQL命令,因此我也包含了create语法。 使用存储过程和正确的参数绑定可以帮助您对抗SQL注入。要注意,SELECT命令需要一个参数/变量来包含包含行的基础。

[编辑]我知道这些代码太优雅了,但是你可以尝试一下这个代码,看看它是否有效?尝试用不同的场景测试它......

答案 1 :(得分:0)

LOCATE(x,y)返回xy的位置(如果x不是子字符串,则返回0)。如果xy的前缀,则为LOCATE(x,y) = 1,这是您用作条件的前缀。如果您不希望'Smith / Jo'匹配'Smith / John / Mark / Jr',那么您需要在条件中添加一些内容以防止此匹配,例如将'/'连接到路径列值,这将影响性能,因为MySQL将无法使用path列上的任何索引。至于找到最长的路径匹配(“最好”是一个非常非描述性的词,通常应该避免),你可以使用排序来获得最长的,LIMIT来忽略更短的结果。

SELECT val2
  FROM tbl
  WHERE (path = ? OR LOCATE(CONCAT(path, '/'), ?) = 1)
    AND val1 IS NOT NULL
  ORDER BY STRLEN(path)
  LIMIT 1

答案 2 :(得分:0)

总结:
仅使用SQL可能无法按要求执行操作 但是,SQL可以从匹配的键中获取多维数组,而PHP可以将其缩小为一个数组。

如果有人可以改进这一点,只使用SQL(如发布的问题),我们将不胜感激。

SQL:

SELECT * FROM `mytable` WHERE `path` = '$mypath' 
OR (LOCATE(`path`, '$mypath') = 1 AND RIGHT(`path`, 1) = '/') 
ORDER by length(`page`) desc;

PHP:

$results = mysql_query(... sql ...);
$pg = array();
foreach(array_keys($results[0]) as $key)
    foreach($results as $result)
        if ($result[$key]){ $pg[$key] = $result[$key]; continue 2; }

您可以在http://codepad.org/UnyEZJ6a

的实践中看到这一点

注意:

  • locate(由Outis使用),instr(使用的Nonym)是相同的,除了参数的顺序是相反的。
  • 在查询中使用right()以确保仅在正斜杠上拆分路径。
  • OR中使用的括号在技术上是多余的,因为在OR之前评估AND。
  • 如果sql中有解决方案,我被告知会使用group_by命令。

希望这可以帮助别人!