简体   繁体   中英

SQL: How to get cells by 2 last dates from 3 different tables?

I have 3 tables (stars mach the ids from the table before):

product:
prod_id*    prod_name   prod_a_id   prod_b_id   prod_user 

keywords:
key_id**    key_word    key_prod*   kay_country 

data: 
id  dat_id**    dat_date    dat_rank_a  dat_traffic_a   dat_rank_b  dat_traffic_b 

I want to run a query (in a function that gets a $key_id ) that outputs all these columns but only for the last 2 dates(dat_date) from the 'data' table for the key_id inserted - so that for every key_word - I have the two last dat_dates + all the other variables included in my SQL query:

So... This is what I have so far. and I don't know how to get only the MAX vars. I tried using "max(dat_date)" in different ways that didn't work.

SELECT prod_id, prod_name, prod_a_id, prod_b_id, key_id, key_word, kay_country, dat_date, dat_rank_a, dat_rank_b, dat_traffic_a, dat_traffic_b
    FROM   keywords
        INNER JOIN data 
            ON keywords.key_id = data.dat_id
        INNER JOIN prods
            ON keywords.key_prod = prods.prod_id

Is there a possability to do this with only one query?

EDIT (FOR IgorM):

public function newnew() { 

    $query = $this->db->query('WITH CTE AS
                                (
                                   SELECT *,
                                         ROW_NUMBER() OVER (PARTITION BY dat_id ORDER BY dat_date ASC) AS                   
                                   RowNo FROM data
                                )
                                SELECT *
                                FROM CTE
                                INNER JOIN keywords 
                                        ON keywords.key_id = CTE.dat_id
                                    INNER JOIN prods
                                        ON keywords.key_prod = prods.prod_id
                                WHERE RowNo < 3
                            ');

    $result = $query->result();

    return $result;

}

This is the error on the output:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CTE AS ( SELECT *, ROW_NUMBER() OVER (' at line 1

WITH CTE AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY dat_id ORDER BY dat_date ASC) AS RowNo FROM data ) SELECT * FROM CTE INNER JOIN keywords ON keywords.key_id = CTE.dat_id INNER JOIN prods ON keywords.key_prod = prods.prod_id WHERE RowNo < 3

For SQL

WITH CTE AS
    (
       SELECT *,
             ROW_NUMBER() OVER (PARTITION BY dat_id ORDER BY dat_date ASC) AS                   
       RowNo FROM data
    )
    SELECT *
    FROM CTE
    INNER JOIN keywords 
            ON keywords.key_id = CTE.dat_id
        INNER JOIN prods
            ON keywords.key_prod = prods.prod_id
    WHERE RowNo < 3

For MySQL (not tested)

SET @row_number:=0;
SET @dat_id = '';

SELECT *, 
@row_number:=CASE WHEN @dat_id=dat_id THEN @row_number+1 ELSE 1 END AS row_number, 
@dat_id:=dat_id AS dat_id_row_count
FROM data d
   INNER JOIN keywords 
         ON keywords.key_id = d.dat_id
   INNER JOIN prods
         ON keywords.key_prod = prods.prod_id
   WHERE d.row_number < 3

The other approach is self joining. I don't want to take credit for somebody else's job, so please look on the following example: ROW_NUMBER() in MySQL

Look for the following there:

SELECT a.i, a.j, (
    SELECT count(*) from test b where a.j >= b.j AND a.i = b.i
) AS row_number FROM test a

I think a window function is the best way to go. without knowing a lot about the structure of the data you can try a subquery of what you are trying to restrict and then joining that to the rest of the data. Then within the where clause restrict the rows you pull back.

select  p.prod_id, p.prod_name, p.prod_a_id, p.prod_b_id, 
        t.key_id, t.key_word, t.kay_country, t.dat_date, 
        t.dat_rank_a, t.dat_rank_b, t.dat_traffic_a, t.dat_traffic_b

from 
      (
          select 
                    k.key_id, k.key_word, k.kay_country, d.dat_date, d.dat_rank_a, 
                    d.dat_rank_b, d.dat_traffic_a, d.dat_traffic_b,
                    row_number() over (partition by dat_id order by dat_date desc) as 'RowNum'
           from     keywords as k
                    inner join 
                    data as d on k.key_id = d.dat_id

        ) as t

        inner join 
        prods as p on t.key_prod = p.prod_id

where tmp.RowNum <=2

If you only want to do this for one key_id at a time (as alluded to in your responses to other answers) and only want two rows, you can just do:

   SELECT p.prod_id,
          p.prod_name,
          p.prod_a_id,
          p.prod_b_id, 
          k.key_id, 
          k.key_word, 
          k.key_country, 
          d.dat_date, 
          d.dat_rank_a,
          d.dat_rank_b,
          d.dat_traffic_a,
          d.dat_traffic_b
     FROM keywords k
     JOIN data d
       ON k.key_id = d.dat_id
     JOIN prods p
       ON k.key_prod = p.prod_id
    WHERE k.key_id = :key_id /* Bind in key id */
 ORDER BY d.dat_date DESC
    LIMIT 2;

Whether you want this depends on your data structure and whether there is more than one key/prod combination per date.

Another option limiting just the data rows would be:

   SELECT p.prod_id,
          p.prod_name,
          p.prod_a_id,
          p.prod_b_id, 
          k.key_id, 
          k.key_word, 
          k.key_country, 
          d.dat_date, 
          d.dat_rank_a,
          d.dat_rank_b,
          d.dat_traffic_a,
          d.dat_traffic_b
     FROM keywords k
     JOIN (
       SELECT dat_id,
              dat_date,
              dat_rank_a,
              dat_rank_b,
              dat_traffic_a,
              dat_traffic_b
         FROM data
        WHERE dat_id = :key_id /* Bind in key id */
     ORDER BY dat_date DESC
        LIMIT 2
          ) d
       ON k.key_id = d.dat_id
     JOIN prods p
       ON k.key_prod = p.prod_id;

If you want some kind of grouped results for all the keywords, you'll need to look at the other answers.

This is a "groupwise max" problem. Reference . CTE does not exist in MySQL.

I'm not totally clear on how your tables are linked, but here is a stab:

SELECT
    *
FROM
  ( SELECT  @prev := '', @n := 0 ) init
JOIN
  ( SELECT  @n := if(k.key_id != @prev, 1, @n + 1) AS n,
            @prev := k.key_id,
            d.*, k.*, p.*
        FROM  data d
        JOIN  keywords k  ON k.key_id = d.dat_id
        JOIN  prods p     ON k.key_prod = p.prod_id
        ORDER BY
            k.key_id   ASC,
            d.dat_date ASC
  ) x
WHERE  n <= 2
ORDER BY  k.key_id, n;

you can use this query:

select prod_id, prod_name, prod_a_id, prod_b_id, key_id, key_word, 
kay_country, dat_date, dat_rank_a, dat_rank_b, dat_traffic_a, dat_traffic_b
from keywords where dat_date in (
 SELECT MAX(dat_date) FROM keywords temp_1 
where temp_1.prod_id = keywords.prod_id
union all 
SELECT MAX(dat_date) FROM keywords
WHERE dat_date NOT IN (SELECT MAX(dat_date ) FROM keywords temp_2 where
temp_2.prod_id = keywords.prod_id)
 )

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