简体   繁体   中英

MYSQL query closest match from a second table

Hi I have 2 tables structured as follows

cdr

src  | bill sec   | clean_dst
------------------------------
100  | 10        | 18006927753
100  | 22        | 18006927753
100  | 9         | 441138973356


dialing_codes

id    | dial_code  | tele2id
-----------------------------
1     | 1         | 1422
2     | 1800      | 1433
3     | 441       | 1024
4     | 4413      | 1086

I need to get the tele2id for the closest match in dial_code against clean_dst my best effort so far is

$query = "SELECT tele2id, dial_code FROM dialing_codes ORDER by dial_code DESC";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
while($row = $result->fetch_assoc()) {
$tele2id = $row['tele2id'];
$dialcode = $row['dial_code'];  
$query2 = "SELECT clean_dst FROM cdr WHERE clean_dst LIKE '".$dialcode."%'";
$result2 = $mysqli->query($query2) or die($mysqli->error.__LINE__);
while($row2 = $result2->fetch_assoc()) {

Which I thought was working but on closer inspection it only returns the correct result the first time if a clean_dst is repeated

eg

clean_dst    dial_code     tele2id
18006927753  1800          1433
18006927753  1             1422

What am i doing wrong? Thanks

If it helps I need the result with the most matching digits?

Please try this query:

select dial_code, clean_dst from cdr c, dialing_codes d where c.clean_dst
  like concat(d.dial_code, '%');

You don't need to code all that logic in php. MySQL gives you the functions and comparisons to do it natively in SQL, which is simpler and much more concise.

Hope this helps.

Although not in php, this one sql can handle your first and secondary query all in one... AND properly handle returning the longest matching entry per dial.

select 
      PQ.clean_dst,
      PQ.dial_code,
      PQ.tele2id,
      @Rank := if( @lastDst = PQ.clean_dst, @Rank +1, 1 ) as dialRank,
      @lastDst := PQ.clean_dst as ForNextRowCompare
   from 
      ( SELECT distinct
              cdr.clean_dst,
              dc.dial_code,
              dc.tele2id,
              length( trim( dc.dial_code )) as Longest
           from 
              cdr
                 JOIN dialing_codes dc
                    on cdr.clean_dst like concat( dc.dial_code, '%' )
           order by
              cdr.clean_dst,
              Longest DESC ) PQ,
      ( select @lastDst := '',
               @Rank := 0 ) sqlvars
   having
      dialRank = 1

The first part is the inner query resulting in alias "PQ" (preQuery). It is getting a list of distinct combinations for any call data record to its matching POSSIBLE dial codes. Critical component is to put the order by each phone number dialed, THEN based on the longest dial code in descending order. This will put your "1800" at the top of the list per phone number using it.

Next comes the outer query where the MySQL @variables are applied. These work like in-line programming loop for you and goes for every record in the "PQ" result set. It starts the variables with blank and zero respectively.

Every record compares its dialed number to the last dialed number record (in cases like your 1800 and 1 multiple return sets). If they ARE the same phone, add 1 to the existing @Rank, otherwise, it is a change in phone numbers... always start a phone number change back to rank 1. THEN, it assigns the @lastDst to the phone number it just processed so it can be the basis of the next phone record being tested.

At the end is a HAVING clause to only include those of DialRank = 1

So, per your record set samples, the query would result in records looking something like...

Dial Number    Dial_Code  Tele2ID   Longest  DialRank   ForNextRowCompare
18006927753    1800       1433      4        1          18006927753        <-- Keep this
18006927753    1          1422      1        2          18006927753
441138973356   441        1024      3        1          441138973356       <-- Keep this

Feedback per comment. TO handle your update, you can just wrap it up

update cdr,
   ( full query ) as FromThisQuery
  where cdr.clean_dst = FromThisQuery.clean_dst
  set tele2id = FromThisQuery.tele2id

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM