I have an SQL query like below:
SELECT a.name_prov AS prov,city,a.cases
FROM
(SELECT c.name_prov,b.city,a.cases,
ROW_NUMBER() OVER (PARTITION BY c.name_prov ORDER BY CAST(a.cases AS INT)DESC) AS rn
FROM tb_cases a
JOIN tb_city b ON a.id_city = b.id_city
JOIN tb_prov c ON a.id_prov = c.id_prov
ORDER BY c.name_prov
) a
ORDER BY a.name_prov,rn
How do I write the above select statement in CodeIgniter ver 3.x active record?
I suggest you to look into CodeIgniter forum for this kind of questions.
$subQuery = $this->db->select()
->....
->get_compiled_select();
$this->db->select('*')
->from("($subQuery) as t", false);
source: https://forum.codeigniter.com/showthread.php?tid=70943
Also, for the query you provided, you don't need a subquery:
SELECT c.name_prov as prov, b.city, a.cases, ROW_NUMBER() OVER (PARTITION BY c.name_prov ORDER BY CAST(a.cases AS INT) DESC) AS rn
FROM tb_cases a
JOIN tb_city b ON a.id_city = b.id_city
JOIN tb_prov c ON a.id_prov = c.id_prov
ORDER BY prov, rn
this should be equivalent to your query.
Related
I've got an SQL query:
SELECT d.device_name, d.device_category
FROM devices d
JOIN (
SELECT device_category, COUNT(*) AS cnt FROM devices GROUP BY device_category
) c ON c.device_category = d.device_category
ORDER BY c.cnt DESC
And now I need to write it (at least, I would like to) in the SQLAlchemy ORM format.
My attempt is this:
sub_dquery = db.session.query(Devices.device_category, func.count('*')).group_by(Devices.device_category).subquery()
long_dquery = db.session.query(Devices.device_name, Devices.device_category).join(sub_dquery).desc()
I don't know how to implement this part:
c ON c.device_category = d.device_category
This looks pretty close:
with Session(engine) as session:
sub_dquery = (
session.query(Devices.device_category, func.count().label("cnt"))
.group_by(Devices.device_category)
.subquery("c")
)
long_dquery = (
session.query(Devices.device_name, Devices.device_category)
.join(sub_dquery, sub_dquery.c.device_category == Devices.device_category)
.order_by(sub_dquery.c.cnt.desc())
)
print(long_dquery)
"""
SELECT devices.device_name AS devices_device_name, devices.device_category AS devices_device_category
FROM devices
JOIN (
SELECT devices.device_category AS device_category, count(*) AS cnt
FROM devices GROUP BY devices.device_category
) AS c ON c.device_category = devices.device_category
ORDER BY c.cnt DESC
"""
I have this query:
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls.ProdServiceID
FROM Products prod
LEFT JOIN ProductServices ls ON ls.ProdServiceID=(SELECT ProdServiceID FROM
ProductServices WHERE ProductID=prod.ProductID ORDER BY Modified DESC LIMIT
1) ;
This query returns 175 rows
I want to convert this to JOIN.
I used below query:
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls1.ProductServicesID
FROM Products prod
inner join ProductServices ls on ls.ProductID=prod.ProductID
inner JOIN (SELECT ProductServicesID, ProductID, max(Modified) as Modified
FROM
ProductServices group by Modified) as ls1 ON ls.ProductServicesID =
ls1.ProductServicesID and ls.Modified = ls1.Modified and ls.ProductID =
ls1.ProductID;
which doesn't return correct result. Can I get some direction on this.
The purpose is to optimize the query. Would it be good idea to use join in place of original query.
Thanks!
Try this:
SELECT ProductID
, Name
, ProdExtID
, ProdServiceID
FROM
(
SELECT prod.ProductID
, prod.Name
, prod.ProdExtID
, ls.ProdServiceID
, RANK() OVER(PARTITION BY ls.ProdServiceID ORDER BY ls.Modified DESC) AS rnk
FROM Products prod
LEFT JOIN ProductServices ls ON ls.ProductID=prod.ProductID
) x
WHERE rnk = 1
So basically: your join needs to be on ProductID but you only want the most recent ProdServiceID, right?
try this select query please.
Here you get the serviceid which corresponds to productid and the last modiied
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls.ProdServiceID
FROM Products prod
LEft join ProductServices ls on ls.ProductID=prod.ProductID
inner JOIN (SELECT ProductID, max(Modified) as Modified
FROM
ProductServices group by ProductID) as ls1 ON ls.ProductID =
ls1.ProductID and ls.Modified = ls1.Modified;
I developed a system based in MySQL V8.0 and, unfortunately, I need downgrade for the most used version in web hostings, that is V5.6.
My queries are almost all like this:
SELECT tb_d.*, id_classification
FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY '1' ORDER BY od_category ASC, $order_by_gp_mid) AS row_final, tb_c.*
FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY id_category ORDER BY MOD(`row` * $prime_group, 512)) AS rd_category, tb_b.*
FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY '1' ORDER BY od_category ASC, $order_by_gp_mid) AS `row`, tb_a.*
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY id_category ORDER BY od_category ASC, tb_x.$order_by_gp_mid) AS rn_category, tb_x.*
FROM (
SELECT
1, od_category, id_category, `group`, category,
id_post, thumbnail, head, visibility, created_datetime, `view`, yeslike, save,
lk_post_category_pic_uvw.fk_pic,
ROUND((yeslike + total_save) / view, 3) AS rank_ratio
FROM tb_category
JOIN (
SELECT fk_post, fk_category, fk_pic
FROM lk_post_category_pic
UNION
SELECT fk_post, `from`, fk_pic
FROM lk_post_model_pic
JOIN tb_model ON tb_model.id_model = lk_post_model_pic.fk_model
WHERE `from` != ''
) AS lk_post_category_pic_uvw ON lk_post_category_pic_uvw.fk_category = tb_category.id_category
JOIN tb_post ON lk_post_category_pic_uvw.fk_post = tb_post.id_post
LEFT JOIN vw_total_save_by_post ON vw_total_save_by_post.fk_post = tb_post.id_post
WHERE visibility = 'show'
) AS tb_x
) AS tb_a
WHERE rn_category <= 35
) AS tb_b
) AS tb_c
WHERE rd_category = 1
) AS tb_d
JOIN lk_post_classification_pic ON tb_d.id_post = lk_post_classification_pic.fk_post
JOIN tb_classification ON lk_post_classification_pic.fk_classification = tb_classification.id_classification
Being that the variable $order_by_gp_mid can assuming these values:
$order_by_gp_mid = 'created_datetime DESC';
$order_by_gp_mid = 'rank_ratio DESC';
$order_by_gp_mid = '`view` DESC';
$order_by_gp_mid = 'created_datetime DESC';
$order_by_gp_mid = 'created_datetime ASC';
So, the biggest problem here are the lines ROW_NUMBER() OVER(PARTITION BY blabla...).
I need rewrite this queries, and so many others too, for MySQL 5.6.
I already read many topics about here in stackoverflow but, I don't how to do it because my queries are very complexs.
So, I don't know what to do anymore, I'm absolutely exhausted of computer programming.
I need to write a query which involves subquery and do indexing. So, I came up with a query to find the team name which has the Highest build up speed in a year:
SELECT CONCAT(team_long_name, ',', team_short_name) AS TeamName,
EXTRACT(YEAR FROM date) AS Year,
buildUpPlaySpeed
FROM team JOIN
team_attributes
ON team.team_api_id = team_attributes.team_api_id
WHERE
(buildUpPlaySpeed,team_attributes.date) in (SELECT
MAX(buildUpPlaySpeed),team_attributes.date
FROM team_attributes
WHERE team_attributes.date = team_attributes.date
group by team_attributes.date)
ORDER BY date desc;
Indexes are present on date,team_api_id,buildUpPlaySpeed columns.
Any suggestions on how to reduce the cost further??
Yes. Replace the correlated subquery with a join:
SELECT CONCAT (
team_long_name
,','
,team_short_name
) AS TeamName
,EXTRACT(YEAR FROM [DATE]) AS Year
,buildUpPlaySpeed
FROM team
INNER JOIN team_attributes ON team.team_api_id = team_attributes.team_api_id
INNER JOIN (
SELECT MAX(buildUpPlaySpeed) maxbuildup
,team_attributes.[DATE]
FROM team_attributes
WHERE team_attributes.[DATE] = team_attributes.DATE
GROUP BY team_attributes.[DATE]
) x ON buildUpPlaySpeed = x.maxbuildup
AND team_attributes.DATE = x.[DATE]
ORDER BY [DATE] DESC
;
and, for sanity's sake please don't name columns "date" because that's used by SQL. Very confusing.
try this also
SELECT CONCAT(team_long_name,',',team_short_name) AS TeamName,EXTRACT(YEAR FROM DATE) AS Year,buildUpPlaySpeed
FROM team
INNER JOIN team_attributes ON team.team_api_id = team_attributes.team_api_id
INNER JOIN ( SELECT MAX(buildUpPlaySpeed) maxbuildup,team_attributes.DATE FROM team_attributes
WHERE team_attributes.DATE = team_attributes.DATE
GROUP BY team_attributes.DATE ) t1
where buildUpPlaySpeed = t1.maxbuildup AND team_attributes.DATE = t1.DATE ORDER BY DATE DESC;
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
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.
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
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)
)