Using the same query I am trying to list out notices which are not sent. I am closer to query but stuck in how to execute few conditions in where clause based upon certain condition.
I have tried the following query.
SELECT
vtn.*,
vn.v_notice_datetime
FROM
v_templates vt
JOIN v_template_notices vtn ON (vtn.v_template_id = vt.id)
JOIN violations v ON( v.v_template_id = vt.id )
LEFT JOIN vnotices vn ON(vn.vtemplate_notice_id = vtn.id)
WHERE
v.id = 1
AND vn.v_notice_datetime IS NULL
AND vtn.id > (
SELECT max(vn.vtemplate_notice_id)
FROM vnotices vn
WHERE vn.vnotice_datetime IS NOT NULL )
I want to cocatenate following sql code when vn.id IS NOT NULL
*AND vtn.id > ( SELECT max(vn.v_template_notice_id)
FROM v_notices vn WHERE vn.v_notice_datetime IS NOT NULL)*
Is CASE statement good option or any alternative? In research found that the CASE statement degrades the performance but I m not sure how to execute conditional statements in PostgreSQL / MySql?
Just a suggestion
You have left join table column involved in where this work as an inner join ..
you should move the condition for left joined table from where to ON condition
SELECT
vtn.*,
vn.v_notice_datetime
FROM v_templates vt
JOIN v_template_notices vtn ON (vtn.v_template_id = vt.id)
JOIN violations v ON( v.v_template_id = vt.id )
LEFT JOIN vnotices vn ON(vn.vtemplate_notice_id = vtn.id) AND vn.v_notice_datetime IS NULL
WHERE v.id = 1
AND vtn.id > (
SELECT max(vn.vtemplate_notice_id)
FROM vnotices vn
WHERE vn.vnotice_datetime IS NOT NULL )
;
Related
I have a query which gives result as below, how to replace duplicate values with NULL
Query:
SELECT
word.lemma,
synset.definition,
synset.pos,
sampletable.sample
FROM
word
LEFT JOIN
sense ON word.wordid = sense.wordid
LEFT JOIN
synset ON sense.synsetid = synset.synsetid
LEFT JOIN
sampletable ON synset.synsetid = sampletable.synsetid
WHERE
word.lemma = 'good'
Result:
Required Result: all the greyed out results as NULL
First, this is the type of transformation that is generally better done at the application level. The reason is that it presupposes that the result set is in a particular order -- and you seem to be assuming this even with no order by clause.
Second, it is often simpler in the application.
However, in MySQL 8+, it is not that hard. You can do:
SELECT w.lemma,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY w.lemma, ss.definition ORDER BY st.sample) = 1
THEN ss.definition
END) as definition,
ss.pos,
st.sample
FROM word w LEFT JOIN
sense s
ON w.wordid = s.wordid LEFT JOIN
synset ss
ON s.synsetid = ss.synsetid LEFT JOIN
sampletable st
ON ss.synsetid = st.synsetid
WHERE w.lemma = 'good'
ORDER BY w.lemma, ss.definition, st.sample;
For this to work reliably, the outer ORDER BY clause needs to be compatible with the ORDER BY for the window function.
If you are using Mysql 8 try with Rank().. As I didn't have your table or data couldn't test this query.
SELECT
word.lemma
,case when r = 1 synset.definition else null end as definition
,synset.pos
,sampletable.sample
FROM
(
SELECT
word.lemma
,synset.definition
,synset.pos
,sampletable.sample
,RANK() OVER (PARTITION BY synset.definition ORDER BY synset.definition) r
FROM
(
SELECT
word.lemma,
synset.definition,
synset.pos,
sampletable.sample
FROM
word
LEFT JOIN
sense ON word.wordid = sense.wordid
LEFT JOIN
synset ON sense.synsetid = synset.synsetid
LEFT JOIN
sampletable ON synset.synsetid = sampletable.synsetid
WHERE
word.lemma = 'good'
) t
)t1;
I would like to ask, how can I optimize this query:
select
h.jmeno hrac,
n1.url hrac_url,
t.nazev tym,
n2.url tym_url,
ss.pocet_zapasu zapasy,
ss.pocet_minut minuty,
s.celkem_golu goly,
s.zk,
s.ck
from
hraci h
left join
(
select
hrac_id,
tym_id,
count(minut_celkem) pocet_zapasu,
sum(minut_celkem) pocet_minut
from
statistiky_stridani ss
join
zapasy z
on z.id = ss.zapas_id
join
souteze s
on s.id = z.soutez_id
join
souteze_nazev sn
on sn.id = s.soutez_id
where
s.rocnik_id = 2
group by
hrac_id
) ss on ss.hrac_id = h.id
left join
(
select
hrac_id,
tym_id,
sum(typ_id = 1 or typ_id = 3) as celkem_golu,
sum(typ_id = 4) as zk,
sum(typ_id = 5) as ck
from
statistiky st
join
zapasy z
on z.id = st.zapas_id
join
souteze s
on s.id = z.soutez_id
join
souteze_nazev sn
on sn.id = s.soutez_id
where
s.rocnik_id = 2
group by
hrac_id
) s on s.hrac_id = h.id
join
navigace n1
on n1.id = h.nav_id
join
tymy t
on t.id = ss.tym_id
join
navigace n2
on n2.id = t.nav_id
order by
s.celkem_golu desc
limit
10
Because query takes about 1,5 - 2 seconds. For example, table statistiky_stridani has about 500 000 rows and statistiky about 250 000 rows.
This returns EXPLAIN:
Thank you for your help
Don't use LEFT JOIN instead of JOIN unless you really need the empty rows.
Try to reformulate because JOIN ( SELECT ... ) JOIN ( SELECT ... ) optimizes poorly.
Please do not use the same alias (s) for two different tables; it confuses the reader.
Add the composite index INDEX(rocnik_id, soutez_id) to souteze.
LEFT JOIN ... JOIN ... -- Please add parentheses to show whether the JOIN should be before doing the LEFT JOIN or after:
either
FROM ...
LEFT JOIN ( ... JOIN ... )
or
FROM ( ... LEFT JOIN ... )
JOIN ...
It may make a big difference in how the Optimizer performs the query, which may change the speed.
There may be more suggestions; work through those and ask again (if it is still "too slow").
I have a problem that I need a WHERE clause in a subquery that depends on the results of the main Query, otherwise my results would be wrong and the query takes too long / is not executeable.
The circumstances that I need this query to create a view which I need for a search server support the problem that I cannot split this into two queries, nor process it with a script dynamically.
The problem occurs with the following query:
SELECT `s`.`id` AS `seminar_id`, (SUM( `sub`.`seminar_rate` ) / COUNT( `sub`.`seminar_id` )) AS `total_rate`
FROM
(
SELECT (SUM( value ) / COUNT( * )) AS `seminar_rate` , `r`.`seminar_id`
FROM `rating` r
INNER JOIN `rating_item` ri ON `r`.`id` = `ri`.`rating_id`
WHERE `r`.`seminar_id` = `s`.`id`/* <- Here is my problem, this is inacessible */
GROUP BY `r`.`seminar_id`
) AS sub,
`seminar` s
INNER JOIN `date` d
ON `s`.`id` = `d`.`seminar_id`
INNER JOIN `date_unit` du
ON `d`.`id` = `du`.`date_id`
LEFT JOIN `seminar_subject` su
ON `s`.`id` = `su`.`seminar_id`
LEFT JOIN `subject` suj
ON `su`.`subject_id` = `suj`.`id`
INNER JOIN `user` u
ON `s`.`user_id` = `u`.`id`
INNER JOIN `company` c
ON `u`.`company_id` = `c`.`id`
GROUP BY `du`.`date_id`, `sub`.`seminar_id`
This query should calculate a total rate out of ratings for each Seminar.
However my ratings are stored in my "rating" table and should be processed live.
(Sidenote: If you wonder about all the joins: This query has alooot more SELECT'ed fields, I just removed them because they are not nesessary to solve the problem and to make the query look less complicated [I know it still is >.>]...)
The reason is that I want this results to be sortable by my search engine later depending
on the users sort parameters, thatswhy I need it inside this query.
The problem itself is pretty obvious:
ERROR 1054 (42S22): Unknown column 's.id' in 'where clause'
The subselect doesnt know about the results of the main query, is there a solution to bypass this?
Could someone give me a hint to get this working?
Thanks in advance.
Using your subquery in the JOIN you can eliminate the WHERE clause and achieve nearly the same result. Here is your modified query. Hope this solves your problem.
SELECT `s`.`id` AS `seminar_id`, (SUM( `sub`.`seminar_rate` ) / COUNT( `sub`.`seminar_id` )) AS `total_rate`
FROM `seminar` s
INNER JOIN
(
SELECT (SUM( value ) / COUNT( * )) AS `seminar_rate` , `r`.`seminar_id`
FROM `rating` r
INNER JOIN `rating_item` ri ON `r`.`id` = `ri`.`rating_id`
/*WHERE `r`.`seminar_id` = `s`.`id` <- Here is my problem, this is inacessible */
GROUP BY `r`.`seminar_id`
) AS sub ON s.id = sub.`seminar_id`
INNER JOIN `date` d
ON `s`.`id` = `d`.`seminar_id`
INNER JOIN `date_unit` du
ON `d`.`id` = `du`.`date_id`
LEFT JOIN `seminar_subject` su
ON `s`.`id` = `su`.`seminar_id`
LEFT JOIN `subject` suj
ON `su`.`subject_id` = `suj`.`id`
INNER JOIN `user` u
ON `s`.`user_id` = `u`.`id`
INNER JOIN `company` c
ON `u`.`company_id` = `c`.`id`
GROUP BY `du`.`date_id`, `sub`.`seminar_id`
This is my mysql query!
SELECT projects.projects_id,
projects.projects_title,
projects.projects_cost
FROM projects
LEFT JOIN invoice
ON invoice.projects_id = projects.projects_id
LEFT JOIN project_assign
ON project_assign.projects_id=projects.projects_id
WHERE project_assign.assigned_user_id=3
AND (SUM( invoice.invoice_amount) < projects.projects_cost
OR invoice.projects_id is null )
AND project_assign.project_completed_date IS NOT NULL
In this query i want select all row that:
Is not present in other table e.g. (in my case other table is
"invoice")
Or if persent then this condition must hold sum(invoice.invoice_amount) < projects.projects_cost
Thanks.
Divide your problem. Use a UNION. First use one query to select all records that are not present in the first table (Use a LEFT JOIN), union that with the result of your second query which would give you all records meeting your second condition (use an outer join)
//Select all records present in left table
//union
//select all records present in both tables matching your condition.
SELECT projects.projects_id,
projects.projects_title,
projects.projects_cost
FROM projects
LEFT JOIN invoice
ON invoice.projects_id = projects.projects_id
LEFT JOIN project_assign
ON project_assign.projects_id=projects.projects_id
WHERE project_assign.assigned_user_id=3
AND project_assign.project_completed_date IS NOT NULL
UNION
SELECT projects.projects_id,
projects.projects_title,
projects.projects_cost
FROM projects
INNER JOIN invoice
ON invoice.projects_id = projects.projects_id
INNER JOIN project_assign
ON project_assign.projects_id=projects.projects_id
WHERE project_assign.assigned_user_id=3
AND (SUM( invoice.invoice_amount) < projects.projects_cost
AND project_assign.project_completed_date IS NOT NULL
select projects.projects_id, projects.projects_title,projects.projects_cost
from projects
left join invoice
on invoice.projects_id = projects.projects_id
left join project_assign
on project_assign.projects_id=projects.projects_id
where project_assign.assigned_user_id=3 and
((select sum(invoice.invoice_amount) from invoice) < projects.projects_cost or invoice.projects_id is null )
and project_assign.project_completed_date is not null
You cannot put aggregation functions in the where clause. In this case, you can do the aggregation using a subquery and then do the comparison:
SELECT p.projects_id, p.projects_title, p.projects_cost
FROM projects p LEFT JOIN
(select i.projects_id, sum(invoice_amount) as invoice_amount
from invoice i
) i
ON i.projects_id = p.projects_id LEFT JOIN
project_assign pa
ON pa.projects_id = p.projects_id
WHERE pa.assigned_user_id = 3 AND
(i.invoice_amount < p.projects_cost OR i.projects_id is null ) AND
pa.project_completed_date IS NOT NULL;
I a developing in zend and have a rather large mysql query. The query works fine and i get the list I expect. I am doing this using Select->Where.... below is the query.
SELECT DISTINCT `d`.* FROM `deliverable` AS `d` INNER JOIN `groups` AS `g1` ON d.id = g1.deliverable_id INNER JOIN `groupmembers` AS `gm1` ON g1.id = gm1.group_id LEFT JOIN `connection` AS `c` ON d.id = c.downstreamnode_id LEFT JOIN `deliverable` AS `d1` ON c.upstreamnode_id = d1.id INNER JOIN `deliverable` AS `d2` ON CASE WHEN d1.id IS NULL THEN d.id ELSE d1.id END = d2.id INNER JOIN `groups` AS `g` ON d2.id = g.deliverable_id INNER JOIN `groupmembers` AS `gm` ON g.id = gm.group_id WHERE (g1.group_type = 100) AND (gm1.member_id = 1) AND (c.downstreamnode_id IS NULL OR d.restrict_access = 1) AND (g.group_type = 100 OR g.group_type = 110) AND (gm.member_id = 1) AND (d.deliverable_type = 110 OR d.deliverable_type = 100) GROUP BY CASE WHEN c.downstreamnode_id IS NULL THEN d.id ELSE c.downstreamnode_id END
Only problem is when I try to count the rows in a mysql query I only get 1 returned. below is the query
SELECT DISTINCT count(*) AS `rowCount` FROM `deliverable` AS `d` INNER JOIN `groups` AS `g1` ON d.id = g1.deliverable_id INNER JOIN `groupmembers` AS `gm1` ON g1.id = gm1.group_id LEFT JOIN `connection` AS `c` ON d.id = c.downstreamnode_id LEFT JOIN `deliverable` AS `d1` ON c.upstreamnode_id = d1.id INNER JOIN `deliverable` AS `d2` ON CASE WHEN d1.id IS NULL THEN d.id ELSE d1.id END = d2.id INNER JOIN `groups` AS `g` ON d2.id = g.deliverable_id INNER JOIN `groupmembers` AS `gm` ON g.id = gm.group_id WHERE (g1.group_type = 100) AND (gm1.member_id = 1) AND (c.downstreamnode_id IS NULL OR d.restrict_access = 1) AND (g.group_type = 100 OR g.group_type = 110) AND (gm.member_id = 1) AND (d.deliverable_type = 110 OR d.deliverable_type = 100) GROUP BY CASE WHEN c.downstreamnode_id IS NULL THEN d.id ELSE c.downstreamnode_id END
i generate this from by using the same 'select' that generated the first query but I reset the columns and add count in.
$this->getAdapter()->setFetchMode(Zend_Db::FETCH_ASSOC);
$select
->reset( Zend_Db_Select::COLUMNS)
->columns(array('count('.$column.') as rowCount'));
$rowCount = $this->getAdapter()->fetchOne($select);
This method works fine for all my other queries only this one i am having trouble with. I suspect it has something to do the 'CASE' I have in there but it is strange because I am getting the correct rows the the first query. Any ideas. Thanks.
FYI below are two queries that I have working successfully.
SELECT DISTINCT `po`.* FROM `post` AS `po` INNER JOIN `postinfo` AS `p` ON po.postinfo_id = p.id WHERE (p.creator_id = 1) ORDER BY `p`.`date_created` DESC
SELECT DISTINCT count(*) AS `rowCount` FROM `post` AS `po` INNER JOIN `postinfo` AS `p` ON po.postinfo_id = p.id WHERE (p.creator_id = 1) ORDER BY `p`.`date_created` DESC
In this one I have 4 rows returned in the first query and 'int 4' returned for the second one. Does anyone know why it doesnt work for the big query?
Move your DISTINCT.
SELECT COUNT(DISTINCT `po`.*) AS `rowCount` ...
Ok figured it out It was the GROUP BY that was causing only 1 result to be returned. Thanks Interrobang for you help I am sure that using DISTINCT incorrectly will have caused me a headache in the future.
Try using SQL_CALC_FOUND_ROWS in your query?
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows
Using SQL_CALC_FOUND_ROWS is mysql-specific, but it's pretty nice for getting a full record count even when your initial query contains a limit. Once you get the count, don't include SQL_CALC_FOUND_ROWS in subsequent queries for extra records since that will cause extra load on your query.
Your initial query would be:
SELECT SQL_CALC_FOUND_ROWS DISTINCT `d`.* FROM `deliverable` AS `d` INNER JOIN `groups` ...
You'll have to do a subsequent call after your initial query executes to get the count by doing a SELECT FOUND_ROWS().
If you do a little searching, you'll find someone who extended Zend_Db_Select to include this ability.