MySQL getting value in same column as where conditional - mysql

Need some help creating a query that can get me the results I want.
I'm pulling information from 2 tables in the mysql database.
TABLE 1 - tblclients
ID firstname lastname
1 Bob K
2 Mary J
3 Tod M
tblcustomfieldsvalues.RelId = tblclients.ID
TABLE 2 - tblcustomfieldsvalues
ID fieldid RelId value
1 15 3 3500
2 15 2 1500
3 17 3 Calp
4 17 2 Amazon
5 17 2 Calp
TABLE 3 - tblcustomfields (JUST FOR REFERENCE)
ID FieldID name
1 15 Purchase Amount
2 17 Site
Desired Result:
I want to show the Purchase Amount in column 4 (FieldID = 15) where FieldID = 17 and value = 'calp'
ID FirstName LastName Value
1 Tod M 3500
2 Mary J 1500
Current Query:
SELECT tblclients.id, tblclients.firstname, tblclients.lastname, tblcustomfieldsvalues.value FROM tblclients INNER JOIN tblcustomfieldsvalues ON tblclients.id = tblcustomfieldsvalues.relid WHERE tblcustomfieldsvalues.fieldid = 17 AND tblcustomfieldsvalues.value = 'Calp'
Current Result:
ID FirstName LastName Value
1 Tod M Calp
2 Mary J Calp

One approach to this is conditional aggregation:
select c.*, value15 as value
from tblclients c join
(select cfv.relid,
max(case when fieldid = 15 then value end) as value15,
sum(case when fieldid = 17 and value = 'Calp' then 1 else 0 end) as cnt17
from tblcustomfieldsvalues cfv
group by cfv.relid
) cv
where cnt17 > 0;
You can also do this with joins. But you need separate joins for each for each of the fields:
SELECT c.id, c.firstname, c.lastname, cfv15.value
FROM tblclients c INNER JOIN
tblcustomfieldsvalues cfv17
ON c.id = cfv17.relid AND
cvf17.fieldid = 17 AND cfv17.value = 'Calp' INNER JOIN
tblcustomfieldsvalues cfv15
ON c.id = cfv15.relid AND
cvf15.fieldid = 15;

I am not clear what result you are expecting...
First of all I am sure you wrote fieldid=17 to get this result not 47.
If so
Your result is normal. You ask for fieldid 17 and also value 'Calp'.
Do you want fieldid 15 maybe ? Those were the ones has prices...
Or maybe
SELECT tblclients.id, tblclients.firstname, tblclients.lastname, tblcustomfieldsvalues.value FROM tblclients INNER JOIN tblcustomfieldsvalues ON tblclients.id = tblcustomfieldsvalues.relid WHERE tblcustomfieldsvalues.fieldid in (15,17) OR tblcustomfieldsvalues.value = 'Calp'
Your Query:
SELECT tblclients.id, tblclients.firstname, tblclients.lastname, tblcustomfieldsvalues.value FROM tblclients INNER JOIN tblcustomfieldsvalues ON tblclients.id = tblcustomfieldsvalues.relid WHERE tblcustomfieldsvalues.fieldid = 47 AND tblcustomfieldsvalues.value = 'Calp'

Related

SQL to check if the value is not present in table

I am working on following SQL:
select *
from `STUDENTLOC` l,
STUDENT s,
ATTENDANCE a
where l.STUDENTID = s.ID
and l.LOCID = 3
Now I need to make sure that the values are not already present in ATTENDANCE table. It has following structure:
ID StudentID ScheduleID
1 6 6
2 3 3
It is a simple list where I need to display list of students whose record have not been added in ATTENDANCE table.
You can use not exists:
select *
from `STUDENTLOC` l
join STUDENT s on l.STUDENTID = s.ID
where not exists (
select 1
from ATTENDANCE a
where a.STUDENTID = l.STUDENTID
)
and l.LOCID = 3
Also, always use modern explicit join syntax instead of comma based join syntax.
Example table student and table payments:
id_student name id id_student datepayment
1 Lisa 1 1 2017-01-01
2 2 1 2017-02-03
3 Asher 3 2 2017-03-05
4 Lee 4 1 2017-03-03
SELECT a.name, a.datepayment
FROM
(SELECT s.name, p.datepayment
FROM
students s
LEFT OUTER JOIN payment p ON s.id_student = p.id_student) AS a
WHERE datepayment IS NULL;
Result:
name datepayment
Asher NULL
Lee NULL

MySQL includes a specific row with order by

Given 2 tables, I want to generate top 3 highest amount from [Purchase] table.
Additional criteria is [Crocs] must be included in top 3 of the records.
I have following SQL, but it cannot generates the result as I wanted (Result A), please guide me on how to pull out the result in Result B. Thank you.
Table (Purchase):
Purchase_ID | StoreID | Amount
------------|---------|--------
1 | 21 | 22
2 | 23 | 13
3 | 25 | 6
4 | 26 | 23
5 | 28 | 18
Table (Store):
Store_ID | StoreName
---------|----------
21 | Adidas
22 | Nike
23 | Puma
24 | New Balance
25 | Crocs
26 | Converse
SQL:
SELECT IF(SUM(amount) IS NULL, 0, SUM(amount)) as totalAmount
FROM (
SELECT a.amount
FROM purchase a
INNER JOIN store b
ON a.store_id = b.storeid
GROUP BY a.amount
HAVING b.StoreName = 'Crocs'
ORDER BY a.amount DESC
LIMIT 3
) t
Result A: $6
Explanation A: Amount of Crocs is $6
Result B: $51
Explanation B: Total Amount of top 3 = $22 (Adidas) + 23 (Puma) + $6 (Crocs)
The answer from scaisEdge is almost right, but the first query could also return a row with crocs and the sorting is wrong (order by max(a.amount) limit 2 means that the lowest 2 results will be shown). Additionally you could wrap the query in another select query to sort the results
SELECT * FROM (
SELECT b.storename, max(a.amount) as maxAmount
FROM purchase a
INNER JOIN store b ON a.store_id = b.storeid
WHERE b.storename != 'crocks'
GROUP BY a.storename
ORDER BY max(a.amount) DESC
LIMIT 2
UNION
SELECT b.storename, a.amount as maxAmount
FROM purchase a
INNER JOIN store b
ON a.store_id = b.storeid
WHERE b.storename='crocks'
ORDER BY a.amount DESC
LIMIT 1
) ORDER BY maxAmount DESC
You could use an union
SELECT b.storename, max(a.amount)
FROM purchase a
INNER JOIN store b
ON a.store_id = b.storeid
GROUP BY a.storename
order by max(a.amount) limit 2
union
SELECT b.storename, a.amount
FROM purchase a
INNER JOIN store b
ON a.store_id = b.storeid
where b.storename='crocks'
try this one:
SELECT sum(amount)as sum_amount,a.store_id,storename,category from
(select amount,store_id from tbl_purchase) as a
inner JOIN
(select store_id,storename,category from tbl_store)as b on a.store_id = b.store_id where b.category = 'supermarket' GROUP BY category

Sql: select only value that join table has value equal to 1

I have these tables in mysql
ADS
ID
1
2
PAYMENTS
id ads_id
1 1
2 1
3 1
4 2
5 2
INSTALLMENTS
id Payment_id paid
1 1 1
2 1 0
3 2 1
4 2 1
5 3 1
6 4 0
7 4 1
8 5 0
I want to get count of ads that have only payments with all installments.paid = 1.
As an example, return value is 2 for ads.id = 1 (only payment.id 2 AND 3 has all installments.paid = 1) and 0 for ads.id = 0
I tried with
SELECT ads.id AS id,
(
select count(*)
from payments
where
(SELECT count(*)
FROM installments
where (installments.payment_id = payments.id AND (installments.paid = 0))) <1
AND payments.ad_id = ads.id
)
FROM ads
LEFT JOIN payments ON ads.id = payments.ad_id
LEFT JOIN installments ON installments.payment_id = payments.id
GROUP BY ads.id
But doesn't work
One way to approach this is using group by and having. To get the ad ids, you don't actually need the ads table, because installments has this information:
select i.ads_id
from installments i join
payments p
on i.payment_id = p.id
group by i.ads_id
having min(i.paid) = 1 and min(i.paid) = max(i.paid);
Note that this is checking both the minimum and maximum value -- just in case some other value were to creep in. If the value could be NULL, you would also want and count(*) = count(i.paid).
Another approach to this would just use not exists or not in:
select a.*
from ads a
where not exists (select 1
from installments i join
payments p
on i.payment_id = p.id
where p.ads_id = a.id and i.paid <> 0
);

mySQL - GROUP BY but get the most recent row

I've got a budget table:
user_id product_id budget created
-----------------------------------------------------------------
1 1 300 2011-12-01
2 1 400 2011-12-01
1 1 500 2011-12-03
2 2 400 2011-12-04
I've also got a manager_user table, joining a manager with the user
user_id manager_id product_id
------------------------------------
1 5 1
1 9 2
2 5 1
2 5 2
3 5 1
What I'd like to do is grab each of the user that's assigned to Manager #5, and also get their 'budgets'... but only the most recent one.
Right now my statement looks like this:
SELECT * FROM manager_user mu
LEFT JOIN budget b
ON b.user_id = mu.user_id AND b.product_id = mu.product_id
WHERE mu.manager_id = 5
GROUP BY mu.user_id, mu.product_id
ORDER BY b.created DESC;
The problem is it doesn't pull the most recent budget. Any suggestions? Thanks!
To accomplish your task you can do as follows:
select b1.user_id,
b1.budget
from budget b1 inner join (
select b.user_id,
b.product_id,
max(created) lastdate
from budget b
group by b.user_id, b.product_id ) q
on b1.user_id=q.user_id and
b1.product_id=q.product_id and
b1.created=q.lastdate
where b1.user_id in
(select user_id from manager_user where manager_id = 5);
I'm assuming here that your (user_id, product_id, created) combination is unique.
For what it's worth, here's the code that returned what I was looking for:
SELECT DISTINCT(b1.id),mu.user_id,mu.product_id,b1.budget,b1.created
FROM budget b1
INNER JOIN (
SELECT b.user_id, b.product_id, MAX(created) lastdate
FROM budget b
GROUP BY b.user_id, b.product_id) q
ON b1.user_id=q.user_id AND
b1.product_id=q.product_id AND
b1.created=q.lastdate
RIGHT JOIN manager_user mu
ON mu.user_id = b1.user_id AND
mu.product_id = b1.product_id
WHERE mu.manager_id = 5;
Thanks for the help Andrea!

Deaggrigate then apply With Rollup

need just a bit more tweaking to my query. I have a table that is filled with assignments and values such as this:
a_inv
assignment_id total
=========================
1 500
Then two tables that are related, categories and channels for the assignment, for example:
a_cat
assignment_id category_id
==============================
1 1
1 11
a_ch
assignment_id channel_id
==============================
1 16
1 25
So what I need to do is figure out how much was spent per category and channel (with rollup).
Here's the query that I got the closest with:
SELECT
ac.category_id, ach.channel_id, ((ia.total/COUNT(DISTINCT ac2.category_id))/COUNT(DISTINCT ach2.channel_id)) AS cur_total
FROM
a_cat ac
LEFT JOIN
a_ch ach ON ach.assignment_id = ac.assignment_id
LEFT JOIN
a_inv ia ON ia.assignment_id = ac.assignment_id
LEFT JOIN
a_cat ac2 ON ach.assignment_id = ac2.assignment_id
LEFT JOIN
a_ch ach2 ON ach2.assignment_id = ac.assignment_id
WHERE
ac.assignment_id = 1
GROUP BY
ac.category_id, ach.channel_id WITH ROLLUP
It gives me a result that is very close to what i need:
category_id channel_id cur_total
=====================================
1 16 125.0000
1 25 125.0000
1 NULL 125.0000 <---- this should be "250.0000"
11 16 125.0000
11 25 125.0000
11 NULL 125.0000 <---- this should be "250.0000"
NULL NULL 125.0000 <---- this should be "500.0000"
Any help is greatly appreciated.
Thanks!
Try this
SELECT category_id, channel_id, SUM(cur_total)
FROM (
SELECT
ac.category_id, ach.channel_id, ((ia.total/COUNT(DISTINCT ac2.category_id))/COUNT(DISTINCT ach2.channel_id)) AS cur_total
FROM
a_cat ac
LEFT JOIN
a_ch ach ON ach.assignment_id = ac.assignment_id
LEFT JOIN
a_inv ia ON ia.assignment_id = ac.assignment_id
LEFT JOIN
a_cat ac2 ON ach.assignment_id = ac2.assignment_id
LEFT JOIN
a_ch ach2 ON ach2.assignment_id = ac.assignment_id
WHERE
ac.assignment_id = 1
GROUP BY
ac.category_id, ach.channel_id
) as t1
GROUP BY category_id, channel_id WITH ROLLUP