I have an SQL join function ready to implement however, if I run the snippet below only rows from wp_tours_tours are returned which also have rows in wp_tours_tours_bookings.
SELECT
wp_tours_tours.*,
SUM(wp_tours_tours_bookings.qty) AS "TotalBookings"
FROM wp_tours_tours
left join wp_tours_tours_bookings ON wp_tours_tours.tour_id=wp_tours_tours_bookings.tour_id
WHERE wp_tours_tours.post_id=12
If I use the below script without the SUM() function in the select statement it returns multiple rows (even those without any rows in wp_tours_tours_bookings)
SELECT
wp_tours_tours.*
FROM wp_tours_tours
left join wp_tours_tours_bookings ON wp_tours_tours.tour_id=wp_tours_tours_bookings.tour_id
WHERE wp_tours_tours.post_id=12
I need to get the first snippet working so that it just returns 0 for "TotalBookings" if it has no rows and to pull through all data from tours_tours even if tours_tours_bookings has no rows.
I would use a correlated subquery here:
select
t.*,
(
select coalesce(sum(tb.qty), 0)
from wp_tours_tours_bookings tb
where tb.tour_id = t.tour_id
) as totalbookings
from wp_tours_tours t
where t.post_id=12
Your query is malformed, because you have an aggregation function (SUM()) and columns that are not aggregated -- but no GROUP BY.
You need a GROUP BY:
SELECT tt.*, COALESCE(SUM(ttb.qty), 0) AS TotalBookings
FROM wp_tours_tours tt LEFT JOIN
wp_tours_tours_bookings ttb
ON tt.tour_id = ttb.tour_id
WHERE tt.post_id = 12
GROUP BY tt.tour_id; -- or whatever the primary key is
You can also use a correlated subquery (which probably has better performance):
SELECT tt.*,
(SELECT COALESCE(SUM(ttb.qty), 0)
FROM wp_tours_tours_bookings ttb
WHERE tt.tour_id = ttb.tour_id
) AS TotalBookings
FROM wp_tours_tours tt
WHERE tt.post_id = 12
Related
I am trying to produce a result that shows duplicates in a table. One method I found for getting duplicates and showing them is to run the select statement again through an inner join. However, one of my columns needs to be the result of a function, and the only thing I can think to do is use an alias, however I can't use the alias twice in a SELECT statement.
I am not sure what the best way to run this code for getting the duplicates I need.
My code below
SELECT EXTRACT(YEAR_MONTH FROM date) as 'ndate', a.transponderID
FROM dispondo_prod_disposition.event a
inner JOIN (SELECT EXTRACT(YEAR_MONTH FROM date) as ???,
transponderID, COUNT(*)
FROM dispondo_prod_disposition.event
GROUP BY mdate, transponderID
HAVING count(*) > 1 ) b
ON ndate = ???
AND a.transponderID = b.transponderID
ORDER BY b.transponderID
SELECT b.ndate, transponderID
FROM dispondo_prod_disposition.event a
INNER JOIN ( SELECT EXTRACT(YEAR_MONTH FROM date) as ndate,
transponderID
FROM dispondo_prod_disposition.event
GROUP BY 1, 2
HAVING COUNT(*) > 1 ) b USING (transponderID)
WHERE b.ndate = ??? -- for example, WHERE b.ndate = 202201
ORDER BY transponderID
Server won't byte on this query, it takes too long to execute:
select prodavac.id, count(artikl.id) as brojartikala, count(poruceno.id) as brojporudzbina from prod_prodavac prodavac
inner join prod_artikl artikl
on prodavac.id=artikl.prodavacid
inner join prod_poruceno poruceno
on prodavac.id=poruceno.prodavacid
group by prodavac.id
On the other hand, both semi-queries run mega fast:
select prodavac.id, count(artikl.id) as brojartikala from prod_prodavac prodavac
inner join prod_artikl artikl
on prodavac.id=artikl.prodavacid
group by prodavac.id
Also the other one:
select prodavac.id, count(poruceno.id) as brojporudzbina from prod_prodavac prodavac
inner join prod_poruceno poruceno
on prodavac.id=poruceno.prodavacid
group by prodavac.id
order by prodavac.id asc
I would really like to do it in one query, so how to merge them correct way? All IDs are indexed integers.
Explain select shows this:
Depending on the relations between the tables and the data, your combined query might not even return the desired result. For a simple count of relations you can use correlated subqueries in the SELECT clause:
select prodavac.id, (
select count(*)
from prod_artikl artikl
where artikl.prodavacid = prodavac.id
) as brojartikala, (
select count(*)
from prod_poruceno poruceno
where poruceno.prodavacid = prodavac.id
) as brojporudzbina
from prod_prodavac prodavac
order by prodavac.id asc
I have a following query:
select
qs.*
from
(
select
tsk.id,
tsk.request_id,
tsk.hash_id
from
user_tasks as usr
inner join unassigned_tasks as tsk on usr.task_id = tsk.id
where
usr.assigned_to = 53
AND tsk.product_id NOT IN (
SELECT
product_id
FROM
product_progresses
WHERE
request_id = tsk.request_id
)
ORDER BY
tsk.id
) as qs <-- this takes about 233ms.
WHERE
qs.id = ( <-- should this subquery execute for every row from outer result-set row?
SELECT
min(qt.id)
FROM
(
select
tsk.id,
tsk.request_id,
tsk.hash_id
from
user_tasks as usr
inner join unassigned_tasks as tsk on usr.task_id = tsk.id
where
usr.assigned_to = 53
AND tsk.product_id NOT IN (
SELECT
product_id
FROM
product_progresses
WHERE
request_id = tsk.request_id
)
ORDER BY
tsk.id
) as qt <-- this takes about 233ms.
WHERE
qt.id > 83934
)
Both qs and qt takes about the same time to execute, i.e. around 233ms.
Also, executing this whole query takes about the same time.
I have a conception that inner query inside where qs.id = (...) executes once for every row in the result-set generated from qs.
In this current case, qs outputs 10 rows.
So I decided to test if the sub-query is executed for each row 10 times.
Here's what I put inside sub-query:
WHERE qs.id = (
SELECT
SLEEP(1)
)
instead of where qs.id = ( select min(qt.id) ... ).
This took about 10.246 s which proves that the inner query is being run for each row.
So with this, shouldn't the initial query take about (qt time) 233 * 10 (rows from qs) = 2330ms?
Is it because select min().. is calculated once only?
In MySQL subqueries within the FROM clause are evaluated before subqueries in the WHERE clause.
Useful article:
https://www.eversql.com/sql-order-of-operations-sql-query-order-of-execution/
In your case, this is causing qs to be fully evaluated before the WHERE clause is factored in. If you want qs to be limited by qt you should be able to achieve that by unnesting qs or moving qt inside qs.
In practice though, rather than use a subquery for the WHERE clause, it would be probably better to use joins.
See SQL select only rows with max value on a column
I have a query which gets the correct result but it is taking 5.5 sec to get the output.. Is there any other way to write a query for this -
SELECT metricName, metricValue
FROM Table sm
WHERE createdtime = (
SELECT MAX(createdtime)
FROM Table b
WHERE sm.metricName = b.metricName
AND b.sinkName='xx'
)
AND sm.sinkName='xx'
In your code, the subselect has to be run for every result row of the outer query, which should be quite expensive. Instead, you could select your filter data in a separate query and join both accordingly:
SELECT `metricName`, `metricValue` FROM Table sm
INNER JOIN (SELECT max(`createdtime`) AS `maxTime, `metricName` from Table b WHERE b.sinkName='xx' GROUP BY `metricName` ) filter
ON (sm.`createdtime` = filter.`maxTime`) AND ( sm.`metricName` = filter.`metricName`)
WHERE sm.sinkName='xx'
Everything in the following query results in one line for each invBlueprintTypes row with the correct information. But I'm trying to add something to it. See below the codeblock.
Select
blueprintType.typeID,
blueprintType.typeName Blueprint,
productType.typeID,
productType.typeName Item,
productType.portionSize,
blueprintType.basePrice * 0.9 As bpoPrice,
productGroup.groupName ItemGroup,
productCategory.categoryName ItemCategory,
blueprints.productionTime,
blueprints.techLevel,
blueprints.researchProductivityTime,
blueprints.researchMaterialTime,
blueprints.researchCopyTime,
blueprints.researchTechTime,
blueprints.productivityModifier,
blueprints.materialModifier,
blueprints.wasteFactor,
blueprints.maxProductionLimit,
blueprints.blueprintTypeID
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
So what I need to get in here is the following table with the columns below it so I can use the values timestamp and sort the entire result by profitHour
tablename: invBlueprintTypesPrices
columns: blueprintTypeID, timestamp, profitHour
I need this information with the following select in mind. Using a select to show my intention of the JOIN/in-query select or whatever that can do this.
SELECT * FROM invBlueprintTypesPrices
WHERE blueprintTypeID = blueprintType.typeID
ORDER BY timestamp DESC LIMIT 1
And I need the main row from table invBlueprintTypes to still show even if there is no result from the invBlueprintTypesPrices. The LIMIT 1 is because I want the newest row possible, but deleting the older data is not a option since history is needed.
If I've understood correctly I think I need a subquery select, but how to do that? I've tired adding the exact query that is above with a AS blueprintPrices after the query's closing ), but did not work with a error with the
WHERE blueprintTypeID = blueprintType.typeID
part being the focus of the error. I have no idea why. Anyone who can solve this?
You'll need to use a LEFT JOIN to check for NULL values in invBlueprintTypesPrices. To mimic the LIMIT 1 per TypeId, you can use the MAX() or to truly make sure you only return a single record, use a row number -- this depends on whether you can have multiple max time stamps for each type id. Assuming not, then this should be close:
Select
...
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Left Join (
SELECT MAX(TimeStamp) MaxTime, TypeId
FROM invBlueprintTypesPrices
GROUP BY TypeId
) blueprintTypePrice On blueprints.blueprintTypeID = blueprintTypePrice.typeID
Left Join invBlueprintTypesPrices blueprintTypePrices On
blueprintTypePrice.TypeId = blueprintTypePrices.TypeId AND
blueprintTypePrice.MaxTime = blueprintTypePrices.TimeStamp
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
Order By
blueprintTypePrices.profitHour
Assuming you might have the same max time stamp with 2 different records, replace the 2 left joins above with something similar to this getting the row number:
Left Join (
SELECT #rn:=IF(#prevTypeId=TypeId,#rn+1,1) rn,
TimeStamp,
TypeId,
profitHour,
#prevTypeId:=TypeId
FROM (SELECT *
FROM invBlueprintTypesPrices
ORDER BY TypeId, TimeStamp DESC) t
JOIN (SELECT #rn:=0) t2
) blueprintTypePrices On blueprints.blueprintTypeID = blueprintTypePrices.typeID AND blueprintTypePrices.rn=1
You don't say where you are putting the subquery. If in the select clause, then you have a problem because you are returning more than one value.
You can't put this into the from clause directly, because you have a correlated subquery (not allowed).
Instead, you can put it in like this:
from . . .
(select *
from invBLueprintTypesPrices ibptp
where ibtp.timestamp = (select ibptp2.timestamp
from invBLueprintTypesPrices ibptp2
where ibptp.blueprintTypeId = ibptp2.blueprintTypeId
order by timestamp desc
limit 1
)
) ibptp
on ibptp.blueprintTypeId = blueprintType.TypeID
This identifies the most recent records for all the blueprintTypeids in the subquery. It then joins in the one that matches.