【问题标题】:MySQL/PHP/PDO + How to get a row for each (duplicate) entry in IN() clasue?MySQL/PHP/PDO + 如何为 IN() 子句中的每个(重复)条目获取一行?
【发布时间】:2018-11-01 09:54:34
【问题描述】:

语言:PHP

数据库:MySQL

我的理解是,如果您在 IN() 子句中有重复条目..它们将被跳过...我需要为 IN() 子句中的每个项目返回/行..无论它们是重复项还是不是。

从阅读中...我相信 [self] JOIN() 是我正在寻找的方法/解决方案..但我不清楚如何在同一张桌子上执行此 JOIN? ..尤其是我已经在下面进行的查询。 (它的工作原理是我需要的......期望不为 IN() 子句中的重复条目返回一行)

但是..我也读过关于 EXISTS() 的文章..也许是更好的方法? (我不是在这里寻找速度。我正在寻找一个可行的解决方案)

我有一个用于显示同一张表的 rextexter 示例..(但是这个查询确实适用于 rextester 但不适用于现实世界或 WAMP..etc)

http://rextester.com/SZRIAN96972

所以我不清楚它是否真的是查询本身? (我读到这将是问题所在,因为在 IN() 子句中会跳过 dups)...因为它在 WAMP 和 REXTESTER 中“有效”...

所以也许它是 PDO 操作的一部分?将数组传递给execute()函数时可能发生了什么?

PDO 片段:

$qMarks = str_repeat('?,', count($brandlist) - 1) . '?'; //create '?' mark placeholders for query, remove last comma and replace with '?'
//preserve IN() order
$displayList_sql = "SELECT * FROM $tablename WHERE CONCAT(brandname, ' ', dosage) IN ($qMarks) ORDER BY FIELD(CONCAT(brandname, ' ', dosage),'". trim(implode("','", $brandlist))."')";             
$displayList_stmt = $conn->prepare($displayList_sql);
$displayList_stmt->execute($brandlist);//make note of passing in array as param to execute() call

传入的 $brandList 数组示例:(带有 dups)

Zyflo CR Extended-release tablet 600 mg','Zyflo CR Extended-release tablet 600 mg',' SEE NOTES BELOW'

所以在这一点上.. 我不清楚 IN() 子句是否是问题所在?或者,如果在将数组传递给 execute() 命令时正在做某事? 有什么东西在 IN() 子句中剥离/跳过重复项?我怎样才能避免这种情况?我希望它是某种自联接..但我看到的所有示例都有硬编码值(不可能)..然后位于初始 IN() 子句中的重复条目用于第二个查询或其他内容。 (我很关注,因为我看不出这如何适用于我的情况)

这是一个工作示例的快速转储,我一直在本地 WAMP 安装上运行该示例:(需要您自己的连接包含文件)

require_once('../db_wamp_pdo.php');
$tablename = 'xxx';

//hard coded list for testing
$brandList_og = array('Zyflo CR Extended-release tablet 600 mg','Zyflo CR Extended-release tablet 600 mg',' SEE NOTES BELOW', 'Alvesco HFA 80mcg');

function get_displayList($tablename, $conn, $brandlist){    
    $rowcount = 0;
    if($brandlist != '' && count($brandlist) > 0){
        $qMarks = str_repeat('?,', count($brandlist) - 1) . '?'; //create '?' mark placeholders for query, remove last comma and replace with '?'       

        //$displayList_sql = "SELECT * FROM $tablename WHERE CONCAT(brandname, ' ', dosage) IN('Zyflo CR Extended-release tablet 600 mg','Zyflo CR Extended-release tablet 600 mg',' SEE NOTES BELOW', 'Alvesco HFA 80mcg') ORDER BY FIELD(CONCAT(brandname, ' ', dosage),'Zyflo CR Extended-release tablet 600 mg','Zyflo CR Extended-release tablet 600 mg',' SEE NOTES BELOW', 'Alvesco HFA 80mcg')";    

        $displayList_sql = "SELECT * FROM $tablename WHERE CONCAT(brandname, ' ', dosage) IN($qMarks) ORDER BY FIELD(CONCAT(brandname, ' ', dosage),'". trim(implode("','", $brandlist))."')";  

        //$displayList_sql = "SELECT * FROM $tablename WHERE CONCAT(brandname, ' ', dosage) FIND_IN_SET($qMarks) ORDER BY FIELD(CONCAT(brandname, ' ', dosage),'". trim(implode("','", $brandlist))."')";   
        //$displayList_sql = "SELECT * FROM $tablename WHERE EXISTS(SELECT CONCAT(brandname, ' ', dosage)) ORDER BY FIELD(CONCAT(brandname, ' ', dosage),'". trim(implode("','", $brandlist))."')";             

        $displayList_stmt = $conn->prepare($displayList_sql);
        $displayList_stmt->execute($brandlist);//make note of passing in array as param to execute() call
        $displayList_stmt->setFetchMode(PDO::FETCH_ASSOC);
        $_displayList = $displayList_stmt->fetchAll(); //returns multi-dimensional array (and correct count)
        $colcount = $displayList_stmt->columnCount();
        $rowcount = $displayList_stmt->rowCount(); 
    }   

    if($rowcount <= 0){
        //nothing returned
    }else{  
        return $_displayList;
    }       
}
$my_displayList = get_displayList($tablename, $conn, array_values(array_filter($brandList_og)));//array_filter() added to get count of only non empty indexes

echo 'BRAND LIST: <br>';
echo var_dump($my_displayList);
echo '<br>';

我一直在输出调试文本.. 'array' 很好,直到它从查询中返回..

所以它要么是 IN() 子句(我目前的理论),我需要帮助以某种方式向这个动态查询添加一个自联接?或者(不太可信)将数组传递到 execute() 行时......事情正在被解析/删除?

【问题讨论】:

  • 不,IN() 子句不会对行进行分组,因此您将收到与 IN 子句匹配的所有行。您可能需要仔细检查您的数据,或者您可以尝试使用 REGEXP。
  • 我没有关注。我的结果不支持您的回答。如果我在传递的 $brandList 数组中有 dup ......它将跳过 dup 并且不为它返回任何内容。 (正如最初的那样)这里的几篇文章实际上声明 IN() 子句中的重复将被跳过/忽略....但是您的说法相反?
  • 它背后的逻辑是.. IN() 子句只不过是一个 OR= 语句.. 所以如果它在第一个 OR 上匹配.. 随后的 OR 已经被检查/通过并因此跳过?在这种情况下,REGEXP 会为我做什么?我需要查询为 IN() 子句中的每个项目返回一个 ROW。不管它们是否重复

标签: php mysql join pdo exists


【解决方案1】:

in() 子句中的重复项在您使用该词的意义上并没有真正被跳过。确实跳过了重复的字段,但这并不重要,因为 IN() 语句的计算结果为 OR 语句。

例如:

select * from table
where table.thing in ('a', 'b')

计算为

select * from table
where 
   table.thing    = 'a'
   or table.thing = 'b'

如果我们在IN() 语句中添加另一个'a',它会被“忽略”,因为原来的'a' 值已经与第一个匹配。让优化器重新写出来是没有意义的。

【讨论】:

  • @Jaconm001 这是正确的。这就是我上面所说的。发帖的原因是如何解决这个问题?我对 MySQL 没有那么丰富的经验,不知道如何添加自联接或这里采取的最佳方法。您尚未发布解决方案/答案。只是一个评论重复我的OP?将您的帖子更改为实际答案.. 如果它有效.. 我会接受它!
  • @whispers 那么你到底想要什么?如果您在IN() 声明中列出了某些内容,您想看两次吗?对于未声明的重复次数,没有真正的 SQL 解决方案特别健壮。
  • @Jaconm001 - 所以你说的不可能? (是的,这正是我想要为 IN() 子句中的每个项目返回一行......即使它是重复的)我在其他帖子中读过关于 (SELF) JOIN?或者可能存在?代替 IN() 子句?
猜你喜欢
  • 2015-09-07
  • 2016-09-27
  • 2014-06-19
  • 1970-01-01
  • 2014-09-20
  • 2016-04-26
  • 1970-01-01
  • 2015-02-14
  • 2012-01-05
相关资源
最近更新 更多