multiplying two columns, different tables... one column null - mysql

In this join query, i am multiplying two columns from different tables, premium & points. What i want to happen is if there are no columns joined in the premium table then the multiplier will be 1.
here is the query
SELECT parent.*,(premiumtable.bid * pointstable.points) as total FROM strings parent
LEFT JOIN premium premiumtable on parent.sid=premiumtable.sid AND premiumtable.paid='1'
LEFT JOIN points pointstable on parent.sid=pointstable.`string-id`
WHERE parent.category=:category AND (parent.submittype='0' OR parent.submittype='3') GROUP BY parent.id ORDER BY total LIMIT 5
So if nothing is joined on the premiumtable instead of premiumtable.bid * pointstable.points it would be 1 * pointstable.points. The premiumtable.bid acts as a multiplier, if it isn't present, i'd want total to equal pointstable.points

Use a case statement:
SELECT parent.*,
case when premiumtable.bid is null
then pointstable.points
else premiumtable.bid * pointstable.points
end as total
FROM strings parent
LEFT JOIN premium premiumtable on parent.sid=premiumtable.sid AND premiumtable.paid='1'
LEFT JOIN points pointstable on parent.sid=pointstable.`string-id`
WHERE parent.category=:category
AND (parent.submittype='0' OR parent.submittype='3')
GROUP BY parent.id
ORDER BY total
LIMIT 5

Try using COALESCE:
SELECT parent.*,
(COALESCE(premiumtable.bid,1) * pointstable.points) as total
FROM strings parent
LEFT JOIN premium premiumtable
on parent.sid=premiumtable.sid AND premiumtable.paid='1'
LEFT JOIN points pointstable
on parent.sid=pointstable.`string-id`
WHERE parent.category=:category
AND (parent.submittype='0' OR parent.submittype='3')
GROUP BY parent.id
ORDER BY total LIMIT 5

Related

MySql sum DISTINCT after join

I have 2 table that join together ( Orders and Order_item)
When I use join I get duplicates records then I eliminate them with DISTINCT, but when I want to get sum the the shipping_price DISTINCT not works because it just eliminate the same price value and I all my prices are same I get 1 not sum !
If I don't use DISTINCT , I get rows per each items in order
SELECT sum(DISTINCT shipping_price) FROM `product_order`
INNER JOIN `product_address`
ON `product_order`.`address_id` = `product_address`.`id`
INNER JOIN `product_item`
ON `product_order`.`id` = `product_item`.`order_id`
WHERE (`status`<>2)
AND (`company_id`=1968)
AND DATE(date)='2021-08-31'
ORDER BY `product_order`.`id` DESC
how to get sum of shipping price correctly ..
data in order_table is
id shipping_price status
100
200
200
100
sum = 600 , but how to get it, if I did't DISTINCT, I get more than one row per order_items row counts that join tho order..
Use a subquery to get your shipping prices. Something like this:
SELECT product_order.id,
SUM(product_item.price * product_item.quantity) shipping_price
FROM product_order
JOIN product_item ON product_order.id = product_item.order_id
GROUP BY product_order.id
The trick here is to get a subquery that delivers exactly one row per order, with the summed-up shipping priced in it. Do your SUM() ... GROUP BY ...` in the subquery. That way you'll avoid any duplication of items.
TEST THIS before you proceed to make sure it works: giving each order id and its shipping price.
Then use it as if it were a table, JOINing it to the rest.
SELECT total.shipping_price,
product_order.id,
product_address.*
FROM product_order
JOIN product_address
ON product_order.id = product_address.order_id
JOIN (
SELECT product_order.id,
SUM(product_item.price * product_item.quantity) shipping_price
FROM product_order
JOIN product_item ON product_order.id = product_item.order_id
GROUP BY product_order.id
) total ON product_order.id = total.id
ORDER BY product_order.id = total.id
Use a subquery instead of a join.
SELECT (
select sum(shipping_price)
FROM product_item
WHERE po.`id` = `product_item`.`order_id`
) as shipping_price
FROM `product_order` po
INNER JOIN `product_address`
ON `product_order`.`address_id` = `product_address`.`id`
WHERE (`status`<>2)
AND (`company_id`=1968)
AND DATE(date)='2021-08-31'
ORDER BY `product_order`.`id` DESC

Count of joined items per group in MySql

I need to get a set of results showing the number of items accumulated for each 'esta' group.
I'm grouping the results by establishment.
Establishment is inner joined to base.
Left joined items are joined against the base.
So in Esta group 2, let's say there are 3 base ids. Each written and verbal record attached to the base ID would count towards that esta in the results set. There can be multiple 'written' or 'verbal' attached to each base record.
I have 6 verbals and 4 writtens in the database, they are spread around the different 'esta' records. In my query, they are all counting towards the first row of the result I get.
I have tried the same with much more data, and regardless of the 'esta', the first row contains every left joined element counted together.
sql:
SELECT
esta.enf_esta_id
,SUM(IF(verbal.enf_verbal_id is not null,1,0)) as verbals
,SUM(IF(written.enf_written_id is not null,1,0)) as writtens
FROM
enf_base base
INNER JOIN enf_esta esta ON esta.enf_esta_id = base.enf_esta_id
LEFT JOIN enf_verbal verbal ON verbal.enf_base_id = base.enf_base_id
LEFT JOIN enf_written written ON written.enf_base_id = base.enf_base_id
WHERE
1=1
GROUP BY
esta.enf_esta_id
result:
enf_esta_id verbals writtens
2 10 10
3 1 0
4 1 1
6 0 0
To prove that the top row is incorrect, here are the results of just getting the verbals and writtens from enf_esta_id 2.
SELECT
COUNT( * ) AS total
FROM
enf_written
INNER JOIN enf_base ON enf_base.enf_base_id = enf_written.enf_base_id
INNER JOIN enf_esta ON enf_base.enf_esta_id = enf_esta.enf_esta_id
WHERE
enf_esta.enf_esta_id =2
yields:
5
And the same with enf_verbal yields 2. adding up the totals of each gives us the correct 10 if we discount the top row of the problem query result.
Can anyone help me get the result I need?
You are multiplying. Say there are 2 verbals and 5 writtens then your joins make these 10 records (i.e. all combinations). Rather then joining tables and aggregating then, you should first aggregate and then join your aggregates. In your case this is aggregates per base ID, which you will finally further aggregate to get estas.
select
base.enf_esta_id,
coalesce(sum(verbal.cnt), 0) as verbals,
coalesce(sum(written.cnt), 0) as writtens
from enf_base base
left join
(
select enf_base_id, count(*) as cnt
from enf_verbal
group by enf_base_id
) verbal on verbal.enf_base_id = base.enf_base_id
left join
(
select enf_base_id, count(*) as cnt
from enf_written
group by enf_base_id
) written on written.enf_base_id = base.enf_base_id
group by base.enf_esta_id;

mysql left join get two queries

ok i have two tables, houses and pictures. what i would like to call is
for each house i would like to call number of pictures for that house and also minimum sort_order number for that photo.
i tried left join in different types, one returns me total photos which is fine ,but doesnt return the min sort order, the other one returns me min sort order but doesnt give me total photos.
my current code is
SELECT properties.p_id, properties.s_property_id, properties.a_property_id,
properties.p_advert_heading, properties.p_postcode, properties.p_price,
properties.p_bedrooms, properties.p_bathrooms, properties.p_status,
properties.p_priority, property_photos.photo_url, property_photos.sort_order, property_photos.photo_local,
COUNT(property_photos.p_id) AS tot_photos
FROM properties
LEFT JOIN property_photos on properties.p_id = property_photos.p_id
WHERE properties.is_archieved = 0 AND properties.p_status = 1 AND properties.a_id = 16
GROUP BY properties.p_id
ie:
house_table
----------
property_id
property_name
photo_table
-----------
photo_id
property_id
sort_order
so i need to find total number of pictures and also the id of the photo with minimum sort_order...
You can get both values most easily by using the substring_index()/group_concat() method to get the first photo_id:
select property_id, count(*) as numphotos,
substring_index(group_concat(photo_id order by sort_order), ',', 1) as min_photo_id
from photo_table pt
group by property_id;
You just need to use GROUP BY and aggregation functions:
SELECT
h.property_id,
h.property_name,
COUNT(p.photo_id) AS photo_count,
MIN(p.sort_order) AS min_sort
FROM house_table AS h
LEFT JOIN photo_table AS p
ON h.property_id = p.property_id
GROUP BY h.property_id

Join tables with specific order

I've got two tables, for example: Teacher and Pupil and table LastViewedPupil with fields who watched him and when (teacherId & pupilId). So I want to return the list of Pupils that was ordered by last viewed date, but there are not all pupils inside LastViewedPupil, but last few for example, I want to show after that ordered by date all left records no matter in wich order, how can I do that?
I can do without last part like
select * from Pupil as p, (
select * from LastViewedPupil lvp where lvp.teacherId = 5 ORDER BY lastViewDate
) as lvp where lvp.pupilId = p.pupilId;
Or should I add corresponding records in LastViewDatePupil for all pupils or need to Join table itself (sounds awkward)?
You should try this one:
SELECT p.*
LEFT JOIN LastViewedPupil lvp ON p.id = lvp
WHERE lvp.teacher_id = 5
ORDER BY lvp.lastViewDate DESC
I'm not sure if that query puts NULL at the beginning or at the end. If that doesn't order the results properly, try this other. I used a CASE for reordering data
SELECT p.*,
CASE WHEN lvp.lvp.lastViewDate IS NULL THEN 1 ELSE 0, END AS notNullfirst FROM Pupil p
LEFT JOIN LastViewedPupil lvp ON p.id = lvp
WHERE lvp.teacher_id = 5
ORDER BY notNullfirst, lvp.lastViewDate DESC

Comparing two values from the same select query

I have a select query which selects all products from my inventory table and joins them with two other tables (tables l_products and a_products)
SELECT
i.*,
b.title,
ROUND((i.price/100*80) - l.price,2) AS margin,
l.price AS l_price,
a.price AS a_price,
ROUND((a.price/100*80) - l.price, 2) AS l_margin
FROM inventory i
LEFT JOIN products b ON i.id = b.id
LEFT JOIN a_products a ON i.id = a.id
LEFT JOIN l_products l ON i.id = l.id
WHERE
a.condition LIKE IF(i.condition = 'New', 'New%', 'Used%')
AND l.condition LIKE IF(i.condition = 'New', 'New%', 'Used%')
This select query will normally give me a table such as...
id, title, condition, margin, l_price, a_price ...
001-new ... new 10 20 10
001-used ... used 10 25 20
002....
Now I need a condition in the query which will ignore all used products that are more expensive (have a higher a_price) than their 'new' counterparts, such as in the example above you can see that 001-used has a higher a_price than 001-new.
How can I achieve this with out having to resolve to using php
FULL JOIN this query with it self on a column which has a uniquely same value for each id prefix.
You may achieve this effect by adding another field to your SELECT call which produces same unique value for 001-new and 001-used, 002-new and 002-used...
Such value generation can be done by defining your own SQL Routine to extract first 3 characters from a column.