MySQL/PHP/PDO + How to get a row for each (duplicate) entry in IN() clasue?

让人想犯罪 __ 提交于 2020-01-17 01:01:12

问题


Language: PHP

DB: MySQL

My understanding is that if you have duplicate entries in the IN() clause.. they will be skipped... I need a return/row for each item in the IN() clause.. regardless if they are dups or not.

From reading... I believe a [self] JOIN() is the approach/solution I am looking for.. but I am not clear on how to do this JOIN on the same table? .. especially with the query I already have going below. (which works how I need it to.. expect for not returning a row for the duplicate entries in the IN() clause)

However.. I have also read about EXISTS() as well.. perhaps a better approach? (I'm not looking for speed here.. I'm looking for a working solution)

I have a rextexter example for displaying a same table.. (however this query DOES work on rextester but not int he real world or WAMP..etc)

http://rextester.com/SZRIAN96972

So I'm not clear if its actually the query itself? (which I read WOULD be the issue, as dups would be skipped in the IN() clause)... because it 'works' in WAMP and REXTESTER...

So perhaps its part of the PDO operations? Maybe something is happening when passing in the array to the execute() function?

PDO Snippet:

$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

Example of the $brandList array being passed in: (with dups)

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

So at this point.. I'm not clear if the IN() clause is the issue? Or if something is being done while passing in the array to the execute() command? Something is stripping/skipping the duplicate(s) in the IN() clause? How can I avoid that? I was hoping it was some sort of self join.. but all examples I saw had hardcoded values (which can not be)..and then the duplicate entries located in the initial IN() clause were used in a second query or something. (I was quite following as I couldnt see how this applied to my situation)

here is a quick dump of a working example, that I have been running on my local WAMP install: (need you own connection include file)

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>';

I have been outputting debug text along the way.. and the 'array' is fine until it comes back from the query..

So its either the IN() clause (my current theory) and I need help somehow adding a self join to this dynamic query? Or (less believable) when passing in the array to the execute() line.. things are getting parsed out/removed?


回答1:


Duplications in the in() clause aren't really skipped in the sense that you're using the word. The duplicated field is indeed skipped, but that doesn't matter because IN() statements evaluate to an OR statement.

For example:

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

evaluates to

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

If we add another 'a' to that IN() statement, it gets 'ignored' because the original 'a' value already matched the first one. Having the optimizer write it out again would be pointless.



来源:https://stackoverflow.com/questions/50470915/mysql-php-pdo-how-to-get-a-row-for-each-duplicate-entry-in-in-clasue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!