I've had troubles when trying to combine the result of 3 queries:
It's the result of 3 queries joined with union, they all pick datas in the same tables except for the last column and I'd like to have the result in one row, which would give me the result 17 in this case but I can't make it works...Any ideas?
thanks
edit: here is the code of the 3 queries used with union from the result above:
select distinct SSN_ID,
TME_ID,
TME_LIBELLE,
convert(varchar,ssn_date_debut,103) as 'Debut',
CONVERT (varchar,ssn_date_fin,103) as 'Fin',
SSN_NB_JOURS,
COUNT (atr_id) as 'Total'
from SESSION
join INSCRIPTION on INS_SSN_ID = SSN_ID
join ACTEUR on INS_ATR_ID = ATR_ID
join theme on tme_id = ssn_tme_id
join ETAT_SESSION on esn_id = ssn_esn_id
join LIEU_SESSION on LSN_SSN_ID =ssn_id
join LIEU on LEU_ID = LSN_LEU_ID
where INS_DT_CONVOCATION is not null
and SSN_ESN_ID = 15
and SSN_JOURNEE_ETUDE = 1
and LEU_NOM is not null
and year(ssn_date_debut) = YEAR(GETDATE())
group by SSN_ID,TME_ID,TME_LIBELLE,ssn_date_debut,ssn_date_fin,SSN_NB_JOURS,ins_ssn_id
union
select distinct SSN_ID,
TME_ID,
TME_LIBELLE,
convert(varchar,ssn_date_debut,103) as 'Debut',
CONVERT (varchar,ssn_date_fin,103) as 'Fin',
SSN_NB_JOURS,
COUNT (atr_id) as 'Total'
from SESSION
join SESSION_FORMATEUR on ASN_SSN_ID = SSN_ID
join ACTEUR anim on anim.ATR_ID = asn_atr_id
join theme on tme_id = ssn_tme_id
join ETAT_SESSION on esn_id = ssn_esn_id
join LIEU_SESSION on LSN_SSN_ID =ssn_id
join LIEU on LEU_ID = LSN_LEU_ID
where SSN_ESN_ID = 15
and SSN_JOURNEE_ETUDE = 1
and LEU_NOM is not null
and year(ssn_date_debut) = YEAR(GETDATE())
group by SSN_ID, TME_ID,
TME_LIBELLE,ssn_date_debut,ssn_date_fin,SSN_NB_JOURS,asn_ssn_id
union
select distinct SSN_ID,
TME_ID,
TME_LIBELLE,
convert(varchar,ssn_date_debut,103) as 'Debut',
CONVERT (varchar,ssn_date_fin,103) as 'Fin',
SSN_NB_JOURS,
COUNT (atr_id) as 'Total'
from SESSION
left join INTERVENANT on ITV_SSN_ID = SSN_ID
left join ACTEUR on ITV_ATR_ID = ATR_ID
join theme on tme_id = ssn_tme_id
join ETAT_SESSION on esn_id = ssn_esn_id
join LIEU_SESSION on LSN_SSN_ID =ssn_id
join LIEU on LEU_ID = LSN_LEU_ID
where SSN_ESN_ID = 15
and SSN_JOURNEE_ETUDE = 1
and LEU_NOM is not null
and year(ssn_date_debut) = YEAR(GETDATE())
group by SSN_ID, TME_ID,
TME_LIBELLE,ssn_date_debut,ssn_date_fin,SSN_NB_JOURS,ITV_SSN_ID
A derived query approach to get SUM on a total column:
SELECT SSN_ID, TIME_ID, TIME_LIBELLE, DEBUT, FIN, SSN_NB_JOURS, SUM(Total) as Total
FROM
(
-- Your original SELECT with UNION
SELECT .. FROM ..
UNION ALL
SELECT .. FROM ..
UNION ALL
SELECT .. FROM ..
) d
GROUP BY SSN_ID, TIME_id, TIME_LIBELLE, DEBUT, FIN, SSN_NB_JOURS
Such way should be a valid syntax on both: mysql and sql server
Use as
select(
select distinct (all columns except the last one) from table) , (select sum(total) from table)
Related
SELECT SUM(commission) as regularincome FROM `tbl_member_commission` where mem_id=2 AND MONTH(cdate) = MONTH(CURRENT_DATE())
SELECT SUM(commission) as crowdfund FROM `tbl_member_comm_month` where mem_id=2 AND MONTH(cdate) = MONTH(CURRENT_DATE())
note:- both of tables have these same column names : commission, mem_id, cdate
If this is the only record in each subquery, you can use CROSS JOIN:
select a.regularincome, b.crowdfund
FROM
(SELECT SUM(commission) as regularincome FROM `tbl_member_commission` where mem_id=2 AND MONTH(cdate) = MONTH(CURRENT_DATE())) as a
cross join
(SELECT SUM(commission) as crowdfund FROM `tbl_member_comm_month` where mem_id=2 AND MONTH(cdate) = MONTH(CURRENT_DATE())) as b
MySQL query:
SELECT SUM(t.transactionAmt) as transactionAmt, c.categoryType, MONTH(str_to_date(t.transactionDate, '%d/%m/%Y')) as transactionMonth, YEAR(str_to_date(t.transactionDate, '%d/%m/%Y')) as transactionYear
FROM transaction_db t INNER JOIN category_db c
ON t.categoryID = c.categoryID
WHERE t.accountID = '12'
GROUP BY c.categoryType, MONTH(str_to_date(t.transactionDate, '%d/%m/%Y'))
ORDER BY MONTH(str_to_date(t.transactionDate, '%d/%m/%Y')) DESC
This is the output:
Is there any way to query it in such a way such that if there are from same transactionMonth, I take the row with categoryType 0 minus away the row with categoryType 1?
For instance, for month 5, I take the 2233 subtract with 464 to get the result.
Thanks in advance!
You can create a view from your query (see Create VIEW Syntax for details), that will be used in subqueries:
SELECT
cat1.transactionAmt - cat2.transactionAmt AS transactionDiff
FROM
(SELECT * FROM MyView WHERE categoryType = 0) AS cat1
JOIN
(SELECT * FROM MyView AS cat1 WHERE categoryType = 1) AS cat2
USING(transactionMonth);
Or try to use Control Flow Functions. For example:
SELECT
SUM(IF(c.categoryType=0, t.transactionAmt, -t.transactionAmt)) as transactionAmt,
MONTH(str_to_date(t.transactionDate, '%d/%m/%Y')) as transactionMonth,
YEAR(str_to_date(t.transactionDate, '%d/%m/%Y')) as transactionYear
FROM
transaction_db t INNER JOIN category_db c
ON t.categoryID = c.categoryID
WHERE t.accountID = '12'
GROUP BY MONTH(str_to_date(t.transactionDate, '%d/%m/%Y'))
ORDER BY MONTH(str_to_date(t.transactionDate, '%d/%m/%Y')) DESC
I have 2 tables (THour_IN and THour_OUT) that have identical schemas:
Columns for THour_IN: Name|date|HourIN
Colums for THour_OUT: Name|date|HourOUT
I make query:
SELECT THour_IN.Name, THour_IN.date, THour_IN.HourIN, THour_OUT.HourOUT FROM THour_IN LEFT JOIN THour_OUT ON (Hour_IN.Name = THour_OUT.Name) AND (Hour_IN.date = THour_OUT.date);
But this is not correct in my case, because I have multiple rows wtih the same date in the tables. The result is:
Name date HourIN HourOUT
AAA 24/11/2013 17:33:06 20:33:27
AAA 24/11/2013 17:33:06 16:36:06
AAA 24/11/2013 07:33:27 20:33:27
AAA 24/11/2013 07:33:27 16:36:06
BBB 18/11/2013 16:36:06
BBB 19/11/2013 07:33:30
BBB 21/11/2013 07:29:24 08:33:22
BBB 22/11/2013 07:33:30 16:34:53
It should be for date 24/11/2013 First HourIN(07:33:27) with Fisrt HourOUT (16:36:06), Second HourIN (17:33:06) with Second HourOUT (20:33:06) Any ideas?
Build segments, then intersect segments.
SELECT
P1.Name, P1.date, P1.HourIN, P1.HourOUT
FROM (
SELECT
I.Name, I.date, I.HourIN, O.HourOUT
FROM
THour_IN AS I
LEFT JOIN THour_OUT AS O
ON (I.Name = O.Name) AND (I.date = O.date)
AND I.HourIN < H.HourOUT
) AS P1
INNER JOIN (
SELECT
I.Name, I.date, I.HourIN, O.HourOUT
FROM
THour_IN AS I
LEFT JOIN THour_OUT AS O
ON (I.Name = O.Name) AND (I.date = O.date)
AND I.HourIN < H.HourOUT
) AS P2
ON P1.name = P2.name AND P1.date = P2.date
AND P1.HourIN <> P2.HourIN and P1.HourOUT <> P2.HourOUT
AND P1.HourOUT > P2.HourIN
AND (P1.HourIN = P2.HourIN AND P1.HourOUT < P2.HourOUT
OR P1.HourIN > P2.HourIN AND P1.HourOUT = P2.HourOUT)
You could use something like so:
SELECT
t.Name,
t.Date,
t.HourIN, (
SELECT Top 1 HourOut
FROM THourOUT o
WHERE o.Name=t.Name AND o.Date=t.date And o.HourOUT>t.HourIN
ORDER BY o.HourOUT,o.ID ) AS HrOut
FROM THourIN AS t
ORDER BY t.Date, t.HourIN;
Note that I have added an ID to the OUT table to ensure that top 1 does not return duplicates.
Here is an example of inserting missing values. It depends on a Numbers table containing integers from 0 or 1 to the highest number of missing values. A number table is useful in many ways.
INSERT INTO thourin
(name,
[date])
SELECT q.name,
q.DATE
FROM (SELECT Outs.name,
Outs.DATE,
Outs.countofout,
Ins.countofin
FROM (SELECT o.name,
o.DATE,
Count(o.name) AS CountOfOut
FROM thourout o
GROUP BY o.name,
o.DATE) AS Outs
LEFT JOIN (SELECT t.name,
t.DATE,
Count(t.name) AS CountOfIn
FROM thourin t
GROUP BY t.name,
t.DATE) AS Ins
ON ( Outs.name = Ins.name )
AND ( Outs.DATE = Ins.DATE )
WHERE (( ( Ins.countofin ) <> [countofout]
OR ( Ins.countofin ) IS NULL ))) AS q,
numbers AS n
WHERE (( ( n.counter ) > 0
AND ( n.counter ) <= [countofout] - [countofin] ))
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
When I run this procedure:
SELECT * FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
WHERE photo_selectedTags.TAGS_COUNTER IN (6,192)
It retrieves rows where TAGS_COUNTER = 6 OR 192
How do I retrieve the rows from 'photo' where TAGS_COUNTER = 6 AND 192?
Corrected: the IN for ALL
The basic idea is this:
SELECT PHOTO_COUNTER
FROM photo_selectedTags
WHERE TAGS_COUNTER in (6, 192)
group by PHOTO_COUNTER
having count(distinct TAGS_COUNTER) = 2 --2 matches # of items in IN clause
You can then do this to get the rest of the columns:
SELECT *
from PHOTO_COUNTER
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
where photo.COUNTER in (
SELECT PHOTO_COUNTER
FROM photo_selectedTags
WHERE TAGS_COUNTER in (6,192)
group by PHOTO_COUNTER
having count(distinct TAGS_COUNTER) = 2 --2 matches # of items in IN clause
) a
Edit
Now that i understand what you want and DB structure, try with this:
SELECT * FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
WHERE photo_selectedTags.TAGS_COUNTER = 6 AND photo_id IN
(SELECT photo_id FROM photoSELECT * FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
WHERE photo_selectedTags.TAGS_COUNTER = 192)
I don't know if photo_id is an actual field of your table, but try to adapt it to your structure
Obviously in the first SELECT don't insert PHOTO_COUNTER because i'll be always the same value and it haven't much sense.
I would propose to use 2 joins
SELECT *
FROM photo
JOIN photo_selectedTags as photo_selectedTags6 -- this join restricts to 'photo.COUNTER' whic have TAGS_COUNTER = 6
ON photo.COUNTER = photo_selectedTags6.PHOTO_COUNTER
AND photo_selectedTags6.TAGS_COUNTER = 6
JOIN photo_selectedTags as photo_selectedTags192 -- this join restricts to 'photo.COUNTER' whic have TAGS_COUNTER = 192
ON photo.COUNTER = photo_selectedTags192.PHOTO_COUNTER
AND photo_selectedTags192.TAGS_COUNTER = 192
Also would be possible to achive it with analytical functions (if supported by your DB)
-- This one works on teradata. Something similar should work on oracle. Don't know about others
SELECT *
FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
QUALIFY max(case when photo_selectedTags.TAGS_COUNTER = 6 then 1 end) over (partition by photo.COUNTER) = 1
AND max(case when photo_selectedTags.TAGS_COUNTER = 192 then 1 end) over (partition by photo.COUNTER) = 1
If you have many values in the list (in addition to 192,6), then this might be possible solution
SELECT *
FROM photo
JOIN
(
SELECT PHOTO_COUNTER, count(distinct TAGS_COUNTER) cnt
FROM photo_selectedTags
WHERE TAGS_COUNTER in (192,6)
HAVING cnt = 2 -- adjust this according to the number of different values
) as pht
ON photo.COUNTER = pht.PHOTO_COUNTER
In subquery only PHOTO_COUNTERs are left which have both (192 and 6), then this is joined