How to write a mysql with respect to the following conditions - mysql

I have 3 table
tmp (pid,title,price)
tmp_studyarea(areaid, tittle, tm_pid)
tmp_module(mid,title, duration, areaid)
I am trying to write a query where I can obtain (tmp.pid, tmp.title, tmp.price, SUM(tmp_module.duration Where tmp_module.areaid = tmpstudyarea.areaid and tmp_studyarea.tmp_pid = tmp.pid) Group by tmp.pid
Here is a query I wrote and i'm unable to get expected results. Help please
SELECT s.title, s.pid, SUM(duration) IN (SELECT a.tmpid, a.areaid, a.title, SUM(m.duration) as duration FROM tmp_studyarea AS a, tmp, tmp_module as m WHERE m.areaid = a.areaid AND a.tmpid = s.pid GROUP BY a.areaid) FROM tmp as s;
Here is my expected resultst
title
pid
duration
tmp Title 1
1
3000
tmp Title 3
4
1000
EDIT
Found a solution
SELECT DISTINCT s.title,s.pid, (SELECT SUM(m.duration) as duration FROM tmp_studyarea AS a, tmp_module as m WHERE m.areaid = a.areaid AND a.tmpid = s.pid GROUP BY a.tmpid) as duration FROM tmp as s, tmp_studyarea, tmp_module GROUP by pid

You must join the 3 tables properly and aggregate:
SELECT t.pid, t.title, t.price,
SUM(m.duration) total_duration
FROM tmp t
INNER JOIN tmp_studyarea s ON s.tmp_pid = t.pid
INNER JOIN tmp_module m ON m.areaid = s.areaid
GROUP BY t.pid, t.title, t.price

Related

Finding top 5 results for multiple values in sql result

I have the following sql query:
SELECT v.venue_id, s.zip, COUNT( * )
FROM bcs_scans s
JOIN bcs_scanners sc ON s.uuid = sc.uuid
JOIN bcs_venues v ON sc.venue_id = v.venue_id
WHERE v.banlist_id = '625'
AND s.del =0
GROUP BY s.zip
ORDER BY COUNT( * ) DESC
Which returns the count of individual zip codes, their count, and associated venue.
How do I go about selecting the top 5 zip codes for each unique venue id?
I believe I can run a subquery that groups results by venue id with the top 5 zip counts, but I am unsure of where to start
Could be you select the result in this way ... a bit complex ..
using the having for extract the value that match the max count group by venue_id from your original query ..
SELECT v.venue_id as venue_id, s.zip as , COUNT( * ) as num
FROM bcs_scans s
JOIN bcs_scanners sc ON s.uuid = sc.uuid
JOIN bcs_venues v ON sc.venue_id = v.venue_id
WHERE v.banlist_id = '625'
AND s.del =0
GROUP BY s.zip
HAVING ( v.venue_id, COUNT( * )) in
(select venue_id, max(num)
from
(SELECT v.venue_id as venue_id, s.zip as , COUNT( * ) as num
FROM bcs_scans s
JOIN bcs_scanners sc ON s.uuid = sc.uuid
JOIN bcs_venues v ON sc.venue_id = v.venue_id
WHERE v.banlist_id = '625'
AND s.del =0
GROUP BY s.zip
ORDER BY COUNT( * ) DESC ) a t
group by venue_id)
ORDER BY COUNT( * ) limit 5

Join with Max and pre-Max row

I have two tables 'sites' and 'index_log'. Table 'sites' is a information about sites(userid, name, description ...) Table index_log have columns date, index_count and siteid. So I want to get last and previous index_log row for each site, where userid = 10. This's my variant:
SELECT ff.id,
ff.siteurl,
ff.last_count,
ff.last_date,
il2.index_count as previous_count,
MAX(il2.date) as previous_date
FROM (
SELECT s.siteurl,
s.id,
il.index_count as last_count,
MAX(il.date) as last_date
FROM sites s
LEFT JOIN index_logs il ON il.siteid = s.id
WHERE s.userid = 10
GROUP BY s.id
) as ff
LEFT JOIN index_logs il2 ON il2.siteid = ff.id AND il2.date < ff.last_date
GROUP BY ff.id
But in this variant index_count column(last and previous) do not match with max date row. I hope for your help.
this will gives you last 2 log entries per sites.id
; with CTE as
(
SELECT s.siteurl, s.id, il.index_count, il.date,
RN = ROW_NUMBER() OVER (PARTITION BY s.id ORDER BY il.date DESC)
FROM sites s
JOIN index_logs il ON il.siteid = s.id
WHERE s.userid = 10
)
SELECT *
FROM CTE
WHERE RN <= 2

Need to Optimise the following MySQL query

I've tried this query successfully with a limit. The following query runs endless without limit:
SELECT o.product_sku
FROM order_table o
WHERE EXISTS (SELECT 1
FROM (SELECT DISTINCT u.type_id,
u.charge_type,
u.billed_weight
FROM ups_table u
WHERE charge_type = 'order_shipping_table'
AND NOT billed_weight = '0'
) dtm
WHERE o.order_id = dtm.type_id)
GROUP BY product_sku
HAVING Count(product_sku) > 1
First of all you don't need these subqueries with DISTINCT and so on:
SELECT o.product_sku
FROM order_table o
WHERE EXISTS (SELECT 1
FROM ups_table u
WHERE charge_type = 'order_shipping_table'
AND NOT billed_weight = '0'
AND type_id=o.order_id
)
GROUP BY product_sku
HAVING Count(product_sku) > 1
I don't know your table structure (what do you want to count in the HAVING?) but you can try to change EXISTS to JOIN:
SELECT o.product_sku
FROM order_table o
JOIN ups_table u on (u.type_id=o.order_id)
AND (u.charge_type = 'order_shipping_table')
AND NOT (billed_weight = '0')
GROUP BY product_sku
HAVING Count(DISTINCT o.order_id) > 1
And you need indexes on o.order_id, o.product_sku, u.type_id,u.charge_type, u.billed_weight

SQl Server 2008 Performance Issue for Count(distinct()) and SUM. How can avoid this issue?

The below one is my query. It's taking 12 seconds for process. I have created the index for T.DataViewId, but it's still taking long time due to Count(distinct()) and Sum. Thanks in Advance.
;WITH my_cte
AS (SELECT T.name AS name,
T.id AS id,
Count(DISTINCT( DD.dynamictableid )) AS counts,
Round(Sum(D.[employees]), 0) AS measure1
FROM dbo.treehierarchy T
LEFT JOIN dbo.dynamicdatatableid DD
ON T.id = DD.hierarchyid
AND T.dataviewid = DD.dataviewid
LEFT JOIN dbo.demo1 D
ON D.[demo1id] = DD.dynamictableid
WHERE T.dataviewid = 2
AND T.parentid = 0
GROUP BY T.id,
T.name)
SELECT name, id, counts, row_num, measure1
FROM (SELECT name,
id,
counts,
Row_number()
OVER(
ORDER BY counts DESC) AS row_num,
measure1
FROM my_cte) innertable
WHERE ( row_num BETWEEN 1 AND 15 )
It looks as if you only need top 15 records of descending counts. It could be done simply like this :
SELECT
TOP 15 T.name AS name,
T.id AS id,
Count(DISTINCT( DD.dynamictableid )) AS counts,
Round(Sum(D.[employees]), 0) AS measure1
FROM
dbo.treehierarchy T
LEFT JOIN
dbo.dynamicdatatableid DD
ON
T.id = DD.hierarchyid
AND
T.dataviewid = DD.dataviewid
LEFT JOIN
dbo.demo1 D
ON
D.[demo1id] = DD.dynamictableid
WHERE
T.dataviewid = 2
AND
T.parentid = 0
GROUP BY
T.id,T.name
ORDER BY
3 DESC

combining multiple sql queries together

I have multiple table for a project (sessions , charges and payments)
To get the sessions i'm doing the following :
SELECT
sess.file_id, SUM(sess.rate * sess.length) AS total
FROM
sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
This will return the amount that a specific student should pay
I also have another table "charges"
SELECT
file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM
file_charges
GROUP BY file_charges.file_id
And finally the payment query :
SELECT
file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM
file_payments
GROUP BY file_payments.file_id
Can i combine those 3 in a way to have :
Total = Payments - (Session + Charges)
Note that it could be negative so i could have file_id that exists in session , charges but not in payments and i could have a payment without sessions or charges ...
Edit : http://sqlfiddle.com/#!2/a90d9
One issue that needs to be addressed is whether one of these queries can be the "driver", in cases where we don't have rows for a given file_id returned by one or more of the queries. (e.g. there might be rows from sess, but none from file_payments. If we want to be sure to include every possible file_id that appears in any of the queries, we can get a list of all possible file_id with a query like this:
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
(NOTE: The UNION operator will remove any duplicates)
To get the specified resultset, we can use that query, along with "left joins" of the other three original queries. The outline of the query will be:
SELECT a.file_id, p.total_payment - ( s.total + c.total_charges)
FROM a
LEFT JOIN s ON s.file_id = a.file_id
LEFT JOIN c ON c.file_id = a.file_id
LEFT JOIN p ON p.file_id = a.file_id
ORDER BY a.file_id
In that statement a is a standin for the query that gets the set of all file_id values (as shown above). The s, c and p are standins for your three original queries, on sess, file_charges and file_payments, respectively.
If any of the file_id values is "missing" from any of the queries, we are going to need to substitute a zero for the missing value. We can use the IFNULL function to handle that for us.
This query should return the specified resultset:
SELECT a.file_id
, IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS t
FROM ( -- all possible values of file_id
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
LEFT
JOIN ( -- the amount that a specific student should pay
SELECT sess.file_id, SUM(sess.rate * sess.length) AS total
FROM sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
) s
ON s.file_id = a.file_id
LEFT
JOIN ( -- charges
SELECT file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM file_charges
GROUP BY file_charges.file_id
) c
ON c.file_id = a.file_id
LEFT
JOIN ( -- payments
SELECT file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM file_payments
GROUP BY file_payments.file_id
) p
ON p.file_id = a.file_id
ORDER BY a.file_id
(The EXPLAIN for this query is not going to be pretty, with four derived tables. On really large sets, performance may be horrendous. But the resultset returned should meet the specification.)
Beware of queries that JOIN all three tables together... that will likely give incorrect results when there are (for example) two (or more) rows for the same file_id in the file_payment table.
There are other approaches to getting an equivalent result set, but the query above answers the question: "how can i get the results of these queries joined together into a total".
Using correlated subqueries
Here's another approach, using correlated subqueries in the SELECT list...
SELECT a.file_id
, IFNULL( ( SELECT SUM(file_payments.paymentAmount) FROM file_payments
WHERE file_payments.file_id = a.file_id )
,0)
- ( IFNULL( ( SELECT SUM(sess.rate * sess.length) FROM sess
WHERE sess.file_id = a.file_id )
,0)
+ IFNULL( ( SELECT SUM(file_charges.price) FROM file_charges
WHERE file_charges.file_id = a.file_id )
,0)
) AS tot
FROM ( -- all file_id values
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
ORDER BY a.file_id
try this
SELECT sess.file_id, SUM(file_payments.paymentAmount) - (SUM(sess.rate * sess.length)+SUM(file_charges.price)) as total_payment FROM sess , file_charges , file_payments
WHERE sess.sessionDone = 1
GROUP BY total_payment
EDIT.
SELECT a.file_id
, IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS tot
FROM (
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
LEFT JOIN (
SELECT sess.file_id, SUM(sess.rate * sess.length) AS total
FROM sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
) s
ON s.file_id = a.file_id
LEFT JOIN (
SELECT file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM file_charges
GROUP BY file_charges.file_id
) c
ON c.file_id = a.file_id
LEFT JOIN (
SELECT file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM file_payments
GROUP BY file_payments.file_id
) p
ON p.file_id = a.file_id
ORDER BY a.file_id
DEMO HERE