Need suggestion formore pretty sql query - mysql

I have this query, it does what it is supposed to do.
It finds all records in table 1that have a match in table 2, and assign a pseudo column value 1.
Then it union a query that retreive all records in table 1 that does not have a match in table 2, and assign a pseudo column value 0.
This works, but I am sure it is possible to do it in a more effective way.
SELECT aplac.*, 1 AS selected
FROM aux_placements aplac
JOIN product_placements pplac
ON pplac.placement_id = aplac.placement_id
WHERE pplac.product_id = 1
UNION
SELECT distinct aplac.*, 0 AS selected
FROM aux_placements aplac
WHERE placement_id NOT IN
(SELECT aplac.placement_id
FROM aux_placements aplac
JOIN product_placements pplac
ON pplac.placement_id = aplac.placement_id
WHERE pplac.product_id = 1)
I was thinking something like this might work:
SELECT aplac.*,
CASE WHEN aplac.placement_id IS NULL
THEN 0
ELSE 1
END AS selected
FROM aux_placements aplac
LEFT OUTER JOIN product_placements pplac
ON pplac.placement_id = aplac.placement_id
WHERE pplac.product_id = 1;
Any suggestion is appreciated.
Thanks in advance
EDIT: sqlfiddle is avaliable here: http://sqlfiddle.com/#!2/57013a/1

You want the product id selection to be part of the join condition - change WHERE to AND.
You want to check whether the join found a matching record in the second table - change aplac.placement_id to pplac.placement_id.
So the next query will work for you:
SELECT aplac.*,
CASE WHEN pplac.placement_id IS NULL
THEN 0
ELSE 1
END AS selected
FROM aux_placements aplac
LEFT OUTER JOIN product_placements pplac
ON pplac.placement_id = aplac.placement_id
AND pplac.product_id = 1;

Related

SQL Subtract from different tables

I'm subtracting values from diferent tables based on ID.
Its like an inventory where I've the tables for Itens In and Itens Out.
What I want to do is to substract the Itens In - Itens Out based on ID of the iten.
I manage to do that, but if an Iten only as an In movement, the query just shows an empty row, when it should show the In movement - Out moment that even if it doesnt exists should be considered as 0, showing in this case only the value of the IN movment.
Can someone help?
Each row in each table represents one item.
TABLE - in_used
id_item_____qnt
1 _________500
2 _________1000
TABLE - out_used
id_item_____qnt
1 _________200
OUTPUT EXPECTED
used_stock
id_item____qnt
1 ________300
2 ________1000 (there's no out movement so it should show only the IN one)
Select
in_used.qnt - out_used.qnt As used_Stock
From
in_used Inner Join
out_used On in_used.id_item = out_used.id_item
If id_item is unique in in_used and there is at most 1 row in out_used then all you need is a LEFT join and COALESCE():
select i.id_item,
i.qnt - coalesce(o.qnt, 0) used_Stock
from in_used i left join out_used o
on i.id_item = o.id_item
If there are more rows use also aggregation:
select i.id_item,
sum(i.qnt) - coalesce(sum(o.qnt), 0) used_Stock
from in_used i left join out_used o
on i.id_item = o.id_item
group by i.id_item
It sounds like you want something like this:
select item, sum(inc)
from ((select item, in_used as inc
from items_in
) union all
(select item, - out_used as inc
from items_out
)
) ii
group by item;
I'm not sure if each row in the two tables represents one item or if there is a counter. If there is a counter, then that should be used instead of 1/-1.
In this case we know that we have id_item in all cases for join results and none of them would be null:
SELECT I.id_item,
SUM(I.qnt) - SUM(O.qnt) AS used_Stock
FROM in_used AS I
JOIN out_used AS O ON I.id_item = O.id_item
GROUP BY id_item
But for general result, you can try below query:
SELECT (CASE
WHEN I.id_item IS NOT NULL THEN I.id_item
ELSE O.id_item
END) AS id_item,
SUM(I.qnt) - SUM(O.qnt) AS used_Stock
FROM in_used AS I
JOIN out_used AS O ON I.id_item = O.id_item
GROUP BY id_item
Hope this works for you!
If you have more then one record per id you can use sum() and must use FULL JOIN if there a no records on both tables or otherwise you can use LEFT JOIN
Select
id_item , coalesce(sum(in_used.qnt),0) - coalesce(sum(out_used.qnt),0) As used_Stock
From
in_used FULL Join
out_used On in_used.id_item = out_used.id_item
GROUP BY id_item

SQL query to select from two tables and return if a value exists

i have two tables:
callcosts
callcosts_custom
is there a way i can select from both tables and return the value of cost from callcosts_custom if the row exists and if it doesnt exist, return the column price from callcosts
with the following WHERE clause:
WHERE callcosts_custom.parent = callcosts.sequence
basically, the callcosts table has all of the default data in and custom data can be added per customer.
the relationship is as follows:
call_costs.sequence = callcosts_custom.parent
so i want to check if a row exists in callcosts_custom for a specific callcosts_custom.customer. if it does, it will return callcosts_custom.cost and if it does not exist to return callcosts_price
updated query:
select b.cost
from call_costs_custom b
where a.sequence = b.parent AND b.customer_seq = '124'
union all
select a.retail
from call_costs a
where a.sequence = '4706' and
not exists (select 1 from call_costs_custom b where b.parent = a.sequence);
Yes . . . this sounds like a prioritization query. This typically looks like
select ccc.price
from callcosts_custom ccc
where ccc.?? = ??
union all
select cc.price
from callcosts ccc
where cc.?? = ?? and
not exists (select 1 from callcosts_custom ccc where ccc.?? = cc.??);
It is unclear from your question what the columns are.
This can be done by left joining the tables (under the assumption that every row must exist in callcosts and may or may not exist in callcosts_custom, but not the other way round) and using coalesce. You haven't given too much information about the tables, but I'm assuming there's some ID column to identify the rows:
SELECT c.id, COALESCE(cc.price, c.price) AS price
FROM callcosts c
LEFT JOIN callcosts_custom cc ON c.id = cc.id
This should work for you:
SELECT IFNULL(cc.cost, c.price) cost
FROM callcosts c
LEFT JOIN cc.parent = c.sequence

mysql COUNT function on two or more columns as per true column value

I am trying to count the number of times the two columns have their assigned value appears. The sql statement I have so far outputs wrong results. Take a look:
SELECT
UPPER(school.district) AS District_name,
COUNT(DISTINCT task1.wp_status) AS Status_New,
COUNT(task1.wp_type) AS Type_Bolehole
FROM school
RIGHT OUTER JOIN task1 ON school.s_name=task1.name
WHERE task1.wp_status="New" OR task1.wp_type="Bolehole"
GROUP BY district AND task1.wp_status="New" AND task1.wp_type="Bolehole"
ORDER BY district;
The two tables am using are as below
School
s_name district
matero lusaka
kema lusaka
naka kabwe
task1
name wp_status wp_type
matero New Bolehole
kema New Bolehole
naka New ProtectedWell
expected output
D_Name Status_New Type_Bolehole
KABWE 1 2
LUSAKA 2 0
I would recommend writing the query like this:
SELECT UPPER(s.district) AS District_name,
SUM(t1.wp_status = 'New') AS Status_New,
SUM(t1.wp_type = 'Bolehole') AS Type_Bolehole
FROM school s JOIN
task1 t1
ON s.s_name = t1.name
WHERE t1.wp_status = 'New' or t1.wp_type = 'Bolehole'
GROUP BY UPPER(s.district)
ORDER BY District_Name;
This makes the following changes:
Table aliases are introduced to make the query easier to read and write.
The join is changed to an inner join. You are selecting on one table and aggregating by the other, so it seems that the query expects a match in both tables.
The group by is based on the actual expression used in the select.
Conditional aggregation is used to get the two columns of counts.
Note: This assumes that the sample results in the question are not correct.
you dont need a right join.. all you need is one conditional sum of the rows
SELECT
UPPER(s.district) AS District_name,
SUM(case when t.wp_status = 'New' then 1 else 0 end) AS Status_New,,
SUM(case when t.wp_type = 'Bolehole' then 1 else 0 end) AS Type_Bolehole
FROM school s
LEFT JOIN task1 t ON s.s_name=t.name
WHERE t.wp_status = 'New' or t.wp_type = 'Bolehole'
GROUP BY District_name
ORDER BY District_name;
DEMO
Try this
SELECT UPPER(school.district) AS District_name,
sum( task1.wp_status ="New") AS Status_New,
sum(task1.wp_type="Bolehole") AS Type_Bolehole FROM school
RIGHT OUTER JOIN task1 ON school.s_name=task1.name
WHERE task1.wp_status="New" OR task1.wp_type="Bolehole"
GROUP BY district
ORDER BY district;
Also in your expected result set bolehole count for firt row should be 0 because task naka don't have type of bolehole
Fiddle Demo

Mysql check if row exists in regular select?

I got an question about mysql. Is it possible to check if an row exists in an external table?
For example, I need to show recent uploaded images and I would like to show some userdata with it and show if the user is online.
My current query is:
SELECT `users`.`username`, `users`.`location`, `users`.`age`, `users`.`dateofbirth`
FROM (`images`)
JOIN `users`
ON `users`.`userid` = `images`.`userid`
WHERE `images`.`active` = 1
LIMIT 12
But I'm missing the 'is online' part. Is it possible to use this in the select? For example if the row exists there would be a value in the select named online and it's value = 1 and if user is not online (no row in table) the value needs to be 0. Is that possible?
Seems like you just need to use a LEFT JOIN on the other table and then a CASE to provide the value:
SELECT `users`.`username`,
`users`.`location`,
`users`.`age`,
`users`.`dateofbirth`,
case when o.`userid` is null then 0 else 1 end UserOnline
FROM (`images`)
JOIN `users`
ON `users`.`userid` = `images`.`userid`
left join online_table o
on `users`.`userid` = o.`userid`
WHERE `images`.`active` = 1
LIMIT 12

SQL Custom Order By

I can't understand why this doesn't work:
select distinct a.QuestionID,a.QuestionName,b.AnswerID,b.AnswerName
from #TempExportList a
join tblAnswers b
on a.QuestionID = b.QuestionID
where a.PaperID=#PaperID
order by (case when a.QuestionName='A' then 0
when a.QuestionName='B' then 1
else a.QuestionID
end)
I get the following error -
ORDER BY items must appear in the
select list if SELECT DISTINCT is
specified.
But this works fine:
select distinct a.QuestionID,a.QuestionName,b.AnswerID,b.AnswerName
from #TempExportList a
join tblAnswers b
on a.QuestionID = b.QuestionID
where a.PaperID=#PaperID
order by a.QuestionID
The error message explains the problem perfectly.
In the first example the ORDER BY item -- CASE WHEN ... END -- doesn't appear in the SELECT list.
In the second example the ORDER BY item -- a.QuestionID -- does appear in the SELECT list.
To fix the first example you'll need to do something like this:
SELECT DISTINCT a.QuestionID, a.QuestionName, b.AnswerID, b.AnswerName,
CASE WHEN a.QuestionName = 'A' THEN 0
WHEN a.QuestionName = 'B' THEN 1
ELSE a.QuestionID
END
FROM #TempExportList AS a
JOIN tblAnswers AS b
ON a.QuestionID = b.QuestionID
WHERE a.PaperID = #PaperID
ORDER BY CASE WHEN a.QuestionName = 'A' THEN 0
WHEN a.QuestionName = 'B' THEN 1
ELSE a.QuestionID
END
You can get around this with a CTE
;WITH T AS
(
SELECT DISTINCT a.QuestionID,a.QuestionName,b.AnswerID,b.AnswerName
FROM #TempExportList a
JOIN tblAnswers b
ON a.QuestionID = b.QuestionID
WHERE a.PaperID=#PaperID
)
SELECT *
FROM T
ORDER BY
CASE
WHEN QuestionName='A'
THEN 0
WHEN QuestionName='B'
THEN 1
ELSE QuestionID
END
I would have thought the message self explanitory.
You have selected a distinct on a.QuestionID,a.QuestionName,b.AnswerID and b.AnswerName. Therefore, there could be rows of data with the same respective values for each of these fields, but a different one for your case statement.
Consider this
a.QuestionID a.QuestionName b.AnswerID b.AnswerName [case statement]
1 'One' 2 'Two' 0
1 'One' 2 'Two' 1
How does the query know which value in the last column to use in the order? Is it 0? It is 1? Quite simply, it can't determine, so it can't use it, hence the error.
The second example is fine, because a.QuestionID does appear in the SELECT list, and the query can happily apply the ordering.