Select query result inside WHERE clause - mysql

Hello I am trying to make a WHERE clause where the condition is the id of the previous selection, example:
SELECT
,P1.caseid
,(SELECT SUM(P1.amount) FROM table_s P1 WHERE P1.status = 4 AND P1.caseid = 20)
as variable
FROM table_s P1 GROUP BY P1.caseid";
let's say each iteration the P1.caseid have value of
20,
45,
20,
How I can insert this value to be the condition of the WHERE clause here: WHERE P1.status = 4 AND P1.caseid = 20
Instead of P1.caseid to be = to 20 it have to be equal to the actual caseid inside the database for each row.
So for each row it will be:
WHERE P1.caseid = 20
WHERE P1.caseid = 45
WHERE P1.caseid = 35
In this case the number is eqaul to the caseid inside the DB.
TABLE NAME: table_s
id | caseid | amount | status
-- | ------------------------
1 | 20 | 10 | 4
2 | 45 | 10 | 4
3 | 20 | 10 | 4
DB is as follows, the result should be:
1 ROW = caseid: 20 amount: 20 status 4
2 ROW = caseid: 45 amount: 10 status 4
Or
$variable = 20
$variable = 10

I think I've worked out what you're asking...
The important note here is to use different aliases for your table in the outer and inner queries. Otherwise you have a serious scope problem. (If two instances of the same entity have the same name, how can MySQL ever know which one you're referring to? It will choose the one in the nearest scope. So, instead, call one of them, for example, lookup.)
SELECT
P1.*,
(
SELECT SUM(lookup.amount)
FROM table_s lookup
WHERE lookup.status = 4
AND lookup.caseid = P1.caseid
)
correlated_sub_query_total_by_caseid
FROM
table_s P1
But that itself can be re-written without the correlated sub-query...
SELECT
P1.*,
SUM(CASE WHEN status = 3 THEN amount END) AS status_3_total,
SUM(CASE WHEN status = 4 THEN amount END) AS status_4_total
FROM
table_s P1
INNER JOIN
table_s lookup
ON lookup.caseid = P1.caseid
GROUP BY
P1.primary_key
That said, you added another comment that seems to contract your question...
the idea is to select the sum of the amount for each caseid and display it. as caseid - sum
For that you just need an aggregation...
SELECT
caseid,
SUM(amount)
FROM
table_s
GROUP BY
caseid
And if you only want to aggregate where the status is 3 or 4...
SELECT
caseid,
SUM(CASE WHEN status = 3 THEN amount ELSE 0 END) status_3_total
SUM(CASE WHEN status = 4 THEN amount ELSE 0 END) status_4_total
FROM
table_s
GROUP BY
caseid

Related

configure query to bring rows which have more than 1 entries

How to get those entries which have more than 1 records?
If it doesn't make sense... let me explain:
From the below table I want to access the sum of the commission of all rows where type is joining and "they have more than 1 entry with same downmem_id".
I have this query but it doesn't consider more entries scenario...
$search = "SELECT sum(commission) as income FROM `$database`.`$memcom` where type='joining'";
Here's the table:
id mem_id commission downmem_id type time
2 1 3250 2 joining 2019-09-22 13:24:40
3 45 500 2 egbvegr new time
4 32 20 2 vnsjkdv other time
5 23 2222 2 vfdvfvf some other time
6 43 42 3 joining time
7 32 353 5 joining time
8 54 35 5 vsdvsdd time
Here's the expected result: it should be the sum of the id no 2, 7 only
ie. 3250+353=whatever.
It shouldn't include id no 6 because it has only 1 row with the same downmem_id.
Please help me to make this query.
Another approach is two levels of aggregation:
select sum(t.commission) income
from (select sum(case when type = 'joining' then commission end) as commission
from t
group by downmem_id
having count(*) > 1
) t;
The main advantage to this approach is that this more readily supports more complex conditions on the other members of each group -- such as at most one "joining" record or both "joining" records and no more than two "vnsjkdv" records.
Use EXISTS:
select sum(t.commission) income
from tablename t
where t.type = 'joining'
and exists (
select 1 from tablename
where id <> t.id and downmem_id = t.downmem_id
)
See the demo.
Results:
| income |
| ----- |
| 3603 |
You can use subquery that will find all downmem_id having more than one occurrence in the table.
SELECT Sum(commission) AS income
FROM tablename
WHERE type = 'joining'
AND downmem_id IN (SELECT downmem_id
FROM tablename t
GROUP BY downmem_id
HAVING Count(id) > 1);
DEMO

MySQL duplicate entries search with selective date criteria

Having trouble wrapping my head around having an efficient "duplicate entries" select in a single query.
In the below example, duplicate StockNo can exist spanning multiple Date. I want to search StockNo for duplicate entries, and if at least 1 StockNo record is found within the Date current YEAR-MONTH, then I also need to select its partner that could exist in any other YEAR-MONTH. Is this possible?
Example Query:
SELECT * FROM `sales`
WHERE `StockNo` IN
(SELECT `StockNo` FROM `sales` GROUP BY `StockNo` HAVING COUNT(*) > 1)
AND `Date` LIKE '2016-11-%'
ORDER BY `StockNo`, `TransactionID`;
Example Data:
ID | StockNo | Date
1 | 1 | 2016-11-01
2 | 1 | 2016-11-10
3 | 2 | 2016-11-05
4 | 2 | 2016-10-29
5 | 3 | 2016-10-25
6 | 3 | 2016-10-15
With my example query and data, I have 3 pairs of duplicate entries. It's pretty obvious that I will only return 3 records (ID's 1, 2 & 3) due to AND Date LIKE '2016-11-%', however I need to return ID's 1, 2, 3, 4. I want to ignore ID's 5 & 6 because neither of them fall within the current month.
Hope that makes sense. Thanks for any help you can provide.
SELECT StockNo
FROM sales
GROUP BY StockNo
HAVING SUM(CASE WHEN DATE_FORMAT(Date, '%Y-%m') = '2016-11' THEN 1 ELSE 0 END) > 0
If you also want to retrieve the full records for those matching stock numbers in the above query, you can just add a join:
SELECT s1.*
FROM sales s1
INNER JOIN
(
SELECT StockNo
FROM sales
GROUP BY StockNo
HAVING SUM(CASE WHEN DATE_FORMAT(Date, '%Y-%m') = '2016-11' THEN 1 ELSE 0 END) > 0
) s2
ON s1.StockNo = s2.StockNo
Demo here:
SQLFiddle
Thank you very much Tim for pointing me in the right direction. Your answer was close but it still only returned records from the current month and in the end I used the following query:
SELECT s1.* FROM `sales` s1
INNER JOIN
(
SELECT * FROM `sales` GROUP BY `StockNo` HAVING COUNT(`StockNo`) > 1
AND SUM(CASE WHEN DATE_FORMAT(`Date`, '%Y-%m')='2016-11' THEN 1 ELSE 0 END) > 0
) s2
ON s1.StockNo=s2.StockNo
This one had been eluding me for some time.

MySQL Query to find users still inside room

Below is my database table, where I will have Check In and Check Out entry records for attending the conference room.
id registration_id roomno day type
1 101 1 2 In
2 103 1 2 In
3 101 1 2 Out
4 105 1 2 In
5 103 1 2 Out
6 101 1 2 In
7 103 1 2 In
8 101 1 2 Out
9 105 1 2 In
10 103 1 2 Out
Now, I want to select those records, which are still attending the conference. Condition is like their last record should be type = In. There can be multiple In/Out entries for each user during a day.
Please let me know the quickest possible MySQL query.
Thanks
Answer which I ended up using:
select * from `registrations_inouts` t
group by t.registration_id
having max(id) = max(case when type = 'In' then id end)
order by rand() limit 1;
Here is one method using not exists:
select *
from t
where t.type = 'In' and
not exists (select 1
from t t2
where t2.registration_id = t.registration_id and t2.type = 'Out'
);
Another method uses conditional aggregation:
select t.registration_id
from t
group by t.registration_id
having max(id) = max(case when type = 'In' then id end);
Note: both of these assume that the ids are assigned sequentially in time, so larger ids are later in time.

SQL query - how to construct multiple SUMs (based on different parameters) in one query

Please review my tables below... Is it possible to build a single query capable of
1) calculating the SUM of total_time for all vehicles that have class_id 1 (regardless of feature_id)(result would be 6:35)
2) calculating the SUM of total_time for all vehicles that have class_id 1 AND have feature_id 2(result would be 5:35 based on vehicle_id 22 and 24)
I'm able to get the results in two seperate queries, but I was hoping to retrieve them in one single query.... something like:
SELECT
SUM((CASE WHEN (VEHICLE_TABLE.class_id = 1) then LOG_TABLE.total_time else 0 end)) **AS TOTAL_ALL**,
...here goes statement for 2)... AS TOTAL_DIESEL...
FROM LOG_TABLE, VEHICLE_TABLE .....
WHERE VEHICLE_TABLE.vehicle_id = LOG_TABLE.vehicle_id ......
TABLE 1: LOG_TABLE (vehicle_id is NOT unique)
vehicle_id | total_time
--------------|--------------
22 2:00
22 0:30
23 1:00
24 2:20
24 0:45
TABLE 2: VEHICLE_TABLE (vehicle_id is unique)
vehicle_id | class_id
--------------|--------------
22 1
23 3
24 1
TABLE 3: VEHICLE_FEATURES_TABLE (vehicle_id is NOT unique but feature_id is unique per vehicle_id)
vehicle_id | feature_id
--------------|--------------
22 1
22 2
23 1
23 2
23 6
24 2
24 6
SELECT SUM(lt.total_time) AS TOTAL_ALL,
SUM(CASE WHEN (vft.feature_id IS NOT NULL) then LOG_TABLE.total_time else 0 end) AS FEATURE_TOTAL
FROM VEHICLE_TABLE vt
JOIN LOG_TABLE lt
ON vt.vehicle_id = lt.vehicle_id
LEFT JOIN VEHICLE_FEATURES_TABLE vft
ON vt.vehicle_id = vft.vehicle_id AND vft.feature_id = 2
WHERE vt.class_id = 1
It seems that there is not much point in putting both of them in one query unless you want the results together.
If so, just add a UNION between the 2 queries.
If you want to have both values in the same row try something like this:
SELECT (SELECT Sum(X)
FROM TBL
WHERE CLASS_ID = 1) AS CLS_id1,
(SELECT Sum(X)
FROM TBL
WHERE CLASS_ID = 1
AND FEATURE_ID = 2) AS CLS_id1_FTR_ID2

mySQL Query design - calculating a vote score for multiple content items

I have a content items table structured like
| contentid | message | categoryid | userid | dateadded | etc..
15 foo bar 3 4 somedate
16 more foo bar 3 4 somedate
16 foo stuff 3 4 somedate
and a votes table, where direction = 1 = an up vote, and = 2 being a down vote.
| voteid | contentid | userid | direction | dateadded
7 15 4 1 some date
8 15 6 1 some date
9 15 17 2 some date
And I'd like to select a set of content items, having an additional column on the end with its calculated score based on the votes in the votes table.
Previously, I had a 'score' column attached to the content table, and each time a vote was cast, it would update its score. This was done so I wouldnt have to have a more complex query to calculate scores on each SELECT, but I'd like to change this now.
This votes table was designed a while ago, so if changing all the votes values to something other than 1 or 2 (perhaps -1 for a downvote) would make it easier, I will update the entire table.
What would the query be to pull all content items, each with a score in a calculated column?
Assuming the vote "direction" represents up and down votes:
SELECT i.contentid,
SUM(CASE WHEN v.direction = 1 THEN 1
WHEN v.direction = 2 THEN -1
ELSE 0 END) AS Votes
FROM items i
LEFT JOIN votes v
ON i.contentid = v.contentid
GROUP BY i.contentid
HAVING SUM(CASE WHEN v.direction = 1 THEN 1
WHEN v.direction = 2 THEN -1
ELSE 0 END) > -3
SELECT
items.*,
SUM(direction = 1) - SUM(direction = 2) AS score
FROM items
LEFT JOIN votes USING (contentid)
GROUP BY contentid
The reason this works is because a true comparison evaluates to 1 and a false one to 0.