Select Between 2 dates but also select NULL values - mysql

I'm trying to run a query where I select dates between 2 values
OR ( `order_products`.`deleted_at` BETWEEN
'2021-01-01 00:00:00' AND '2021-07-28 23:59:59' )
But I also need to collect order_products with NULL values.
Is this at all possible, as when I put an
OR `order_products`.`deleted_at` IS NULL
Into my code, It seems to just return absolutley everything in the database :-(
My current code, for context is :
SELECT
`orders`.`id`,
`orders`.`reference`,
`orders`.`order_date`,
`orders`.`cancellation_date`,
`order_products`.`description`,
`order_products`.`st_code`,
`order_products`.`supplier_stock_code`,
`order_products`.`status`,
`order_products`.`deleted_at`,
`supplier`.`name`,
order_invoice.created_at AS credit_date,
fitters.account_number AS fitter_account_number,
fitters.name AS fitter
FROM `order_products`
LEFT JOIN `orders` ON (`orders`.`id` = `order_products`.`order_id`)
LEFT JOIN `supplier` ON (`order_products`.`supplier_id` = `supplier`.`id`)
LEFT JOIN `fitters` ON (`orders`.`fitter_id` = `fitters`.`id`)
JOIN `order_invoice` ON (`order_invoice`.`order_id` = `orders`.`id`)
WHERE `cancellation_date` IS null
AND `cancellation_date` BETWEEN '2021-01-01 00:00:00' AND '2021-07-28 23:59:59'
AND `order_invoice`.`status` = 'approved'
OR (`order_products`.`deleted_at` BETWEEN '2021-01-01 00:00:00'
OR `order_products`.`deleted_at` IS NULL
AND '2021-07-28 23:59:59')
AND `order_products`.`product_type` = 'product'
ORDER BY `orders`.`id` ASC

Your syntax is off. You need:
WHERE order_products.deleted_at >= '2021-01-01' AND
order_products.deleted_at < '2021-07-29' OR
order_products.deleted_at IS NULL
Note that I wrote the datetime check using date inequalities, which seems cleaner to me. Also, we don't need any extra parentheses here as AND has higher precedence than OR.

Please try changing the where condition to
WHERE cancellation_date IS null
AND cancellation_date BETWEEN '2021-01-01 00:00:00' AND '2021-07-28 23:59:59'
AND order_invoice.status = 'approved'
OR (order_products.deleted_at IS NULL OR order_products.deleted_at BETWEEN '2021-01-01 00:00:00' AND '2021-07-28 23:59:59')
AND order_products.product_type = 'product'

Related

Is there any way to optimize this MySQL query when merging two query?

I was trying to get the result with product_id, stock, new_cost
SELECT inventory_logs.product_id, ROUND(SUM(inventory_logs.qty + 0), 4) AS stock
FROM products
JOIN inventory_logs on products.id = inventory_logs.product_id
WHERE inventory_logs.`type` = 'as'
AND inventory_logs.`created_at` between '1970-01-01' and '2021-02-22 23:59:59'
AND inventory_logs.`branch_id` = 1
AND inventory_logs.`deleted_at` IS NULL AND products.deleted_at IS NULL
GROUP BY inventory_logs.product_id HAVING stock > 0
above that is the query for getting stock,
duration for query is about 0.031 sec
SELECT inventory_logs.product_id, inventory_logs.new_cost
FROM inventory_logs JOIN(
SELECT product_id, MAX(created_at) AS created_at
FROM inventory_logs
WHERE created_at <= '2021-02-22 23:59:59' AND deleted_at IS NULL
AND `type` = 'as'
AND inventory_logs.`branch_id` = 1
GROUP BY product_id
) i2 ON (inventory_logs.product_id = i2.product_id AND inventory_logs.created_at = i2.created_at)
WHERE `type` = 'as'
AND inventory_logs.`branch_id` = 1
above is the query for getting new_cost, duration for query is also about 0.031 sec
But when I try to merge the above two query into one, the duration of query is 26.016 sec
The query is
SELECT inventory_logs.product_id, ROUND(SUM(inventory_logs.qty = 0), 4) AS stock, sub.new_cost
FROM products
JOIN inventory_logs ON products.id = inventory_logs.product_id
JOIN (
SELECT inventory_logs.product_id, inventory_logs.new_cost
FROM inventory_logs JOIN (
SELECT product_id, MAX(created_at) AS created_at
FROM inventory_logs
WHERE created_at <= '2021-02-22 23:59:59' AND deleted_at IS NULL
AND `type` = 'as'
AND inventory_logs.`branch_id` = 1
GROUP BY product_id
) i2 ON (inventory_logs.product_id = i2.product_id AND inventory_logs.vreated_at
= i2.created_at)
WHERE `type` = 'as'
AND inventory_logs.`branch_id` = 1
) sub ON products.id = sub.product_id
WHERE inventory_logs.`type` = 'as'
AND inventory_logs.`created_at` BETWEEN '1970-01-01' AND '2021-02-22 23:59:59'
AND inventory_logs.`branch_id` = 1
AND inventory_logs.`deleted_at` IS NULL
AND products.deleted_at IS NULL
GROUP BY inventory_logs.product_id HAVING stock > 0
Is there any ways to optimize the above query to make it take lesser time?

Query using group by month

I have problem with the query using group by month. This query returns total_revenue per month. but if month of year doesn't contain any data then total_revnue is increased unnecessarily.
SELECT COUNT(CT.cumTxnReportId),
CT.cumTxnReportId,
CT.ticketNum,
DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y'),
sum(netAmount) AS total_revenue,
D.name,
HOUR(CT.entranceDateTimeUtc) AS entryHour,
HOUR(CT.exitDateTimeUtc) AS exitHour,
CT.entranceDateTimeUtc,
CT.exitDateTimeUtc,
CT.netAmount AS netAmount,
CT.grossAmount,
CT.discountAmount,
CT.rate,
CT.txnType,
CT.ticketType,
CT.txnNum,
CT.numDiscounts
FROM Parkloco.ParkingArea PA
JOIN IParcPro.Device D ON PA.id = D.parkingAreaId
JOIN Parkloco.RateCard RC ON PA.id = RC.parkingAreaId
JOIN IParcPro.CumTxn CT ON D.id = CT.deviceId
WHERE PA.uuid = '27d842c1-7057-11e6-a0eb-1245b0d35d23'
AND (CT.txnType = 'Allowed'
OR CT.txnType = 'Add'
OR CT.txnType = 'Normal'
OR CT.txnType = 'Offline'
OR CT.txnType = 'Repay')
AND ((CT.entranceDateTimeUtc >= '2016-08-01 00:00:00'
AND CT.exitDateTimeUtc <= '2017-04-31 23:59:59'))
AND (RC.state = 'active'
OR RC.state = 'archived')
AND RC.fromDateTimeUtc <= '2017-04-31 23:59:59'
AND (RC.thruDateTimeUtc IS NULL
OR RC.thruDateTimeUtc >= '2016-08-01 00:00:00')
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) >= '0' * 60)
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) < '1441' * 60)
AND CT.numDiscounts=0
AND CT.ticketNum !=0
GROUP BY DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y')
but when I am increasing the range month - at that point of time I am getting unneccessary increment in total_revenue
SELECT COUNT(CT.cumTxnReportId),
CT.cumTxnReportId,
CT.ticketNum,
DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y'),
sum(netAmount) AS total_revenue,
D.name,
HOUR(CT.entranceDateTimeUtc) AS entryHour,
HOUR(CT.exitDateTimeUtc) AS exitHour,
CT.entranceDateTimeUtc,
CT.exitDateTimeUtc,
CT.netAmount AS netAmount,
CT.grossAmount,
CT.discountAmount,
CT.rate,
CT.txnType,
CT.ticketType,
CT.txnNum,
CT.numDiscounts
FROM Parkloco.ParkingArea PA
JOIN IParcPro.Device D ON PA.id = D.parkingAreaId
JOIN Parkloco.RateCard RC ON PA.id = RC.parkingAreaId
JOIN IParcPro.CumTxn CT ON D.id = CT.deviceId
WHERE PA.uuid = '27d842c1-7057-11e6-a0eb-1245b0d35d23'
AND (CT.txnType = 'Allowed'
OR CT.txnType = 'Add'
OR CT.txnType = 'Normal'
OR CT.txnType = 'Offline'
OR CT.txnType = 'Repay')
AND ((CT.entranceDateTimeUtc >= '2016-08-01 00:00:00'
AND CT.exitDateTimeUtc <= '2017-07-31 23:59:59'))
AND (RC.state = 'active'
OR RC.state = 'archived')
AND RC.fromDateTimeUtc <= '2017-07-31 23:59:59'
AND (RC.thruDateTimeUtc IS NULL
OR RC.thruDateTimeUtc >= '2016-08-01 00:00:00')
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) >= '0' * 60)
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) < '1441' * 60)
AND CT.numDiscounts=0
AND CT.ticketNum !=0
GROUP BY DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y')
output such as :
can anyone help me on this? Thanks in advance if you could let me know.
Despite MySQL allow this weird group by rules, in my opinion, you should to avoid use it. I explain, usually, all select clause non aggregate fields should appear on group by clause:
select a,b,c, sum(z)
from t
group by a,b,c
vs
select a,b,c, sum(z)
from t
group by a #<--- MySQL allow this!
Then, if b and c are not in group by, how MySQL figure up the right fields to be selected? Like this on <5.6:
The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate.
In my opinion, in your query has no sense: Look entryHour and total_revenue. One is for an entry the other one is for all month.
I guess you should to rethink the hole sql statement. Because the result of this one is incoherent.
Also, remember this is not 'code revision service'. Please, read how to create a Minimal, Complete, and Verifiable example in order your question also help other users.

MySQL query hanging

I have a mysql query, which runs however it just hangs and doesn't stop. I'm unsure where the query is breaking.
SELECT
TIMESTAMPDIFF(SECOND, '1970-01-01 00:00:00', f.Datestamp) AS Epoch,
f.value AS `Usage`,
q.Name AS Quantity,
q.QuantityID,
units,
PrimeDataItem,
dd.Description
FROM SourceChannels c
JOIN UsageHhourly f ON c.ChanID = f.ChanID
JOIN Quantities q ON c.QuantityID = q.QuantityID
LEFT JOIN DigitalDescriptions dd ON ((c.DigitalDescriptionID = dd.DigitalDescriptionID)
AND f.value = (CASE WHEN dd.Value REGEXP '^[0-9]' = 1 then dd.Value ELSE -1 END))
WHERE
c.EquipmentID = 1496
AND f.DateStamp >= '2016-12-28 00:00:00'
AND f.DateStamp < '2017-01-04 00:00:00'
ORDER BY q.QuantityID, f.datestamp
The question does not provide more en-lighting information. Try to alter your query like in the below example.
SELECT
TIMESTAMPDIFF(SECOND, '1970-01-01 00:00:00', `f`.`Datestamp`) AS `Epoch`,
`f`.`value` AS `Usage`,
`q`.`Name` AS `Quantity`,
`q`.`QuantityID`,
`c`.`units`,
`c`.`PrimeDataItem`,
`dd`.`Description`
FROM `SourceChannels` `c`
INNER JOIN `UsageHhourly` `f` ON `c`.`ChanID` = `f`.`ChanID`
INNER JOIN `Quantities` `q` ON `c`.`QuantityID` = `q`.`QuantityID`
LEFT JOIN `DigitalDescriptions` `dd` ON `c`.`DigitalDescriptionID` = `dd`.`DigitalDescriptionID`
WHERE
`f`.`value` = IF((dd.Value REGEXP '^[0-9]'),1,-1)
AND `c`.`EquipmentID` = 1496
AND `f`.`DateStamp` BETWEEN '2016-12-28 00:00:00' AND '2017-01-04 00:00:00'
ORDER BY `q`.`QuantityID`, `f`.`datestamp`;

Mysql optimization operator 'I N'

I have this query.
I want to optimization this query,because it takes more then 4.sec
![SELECT clerk_id, COUNT(*) AS num
FROM `note`
WHERE note.id IN (
SELECT note.id
FROM `note`
LEFT JOIN conn ON conn.contract_id = note.id
WHERE `type` <>4 AND `type` <>6 AND `cancelled` =0 AND `ebill` <> '' AND activated_datetime > '0000-00-00 00:00:00' AND activated_datetime >= '2011-06-13 00:00:00' AND activated_datetime <= '2011-06-21 23:59:59' AND clerk_code LIKE 'S%'
)
GROUP BY clerk_id][1]
Thanks for suggestions
I think you could write your query as a single one like this:
SELECT clerk_id, COUNT(*)
FROM `contracts`
LEFT JOIN contract_connections ON contract_connections.contract_id = contracts.id
WHERE `type` <>4 AND `type` <>6 AND `cancelled` =0 AND `ebill` <> '' AND activated_datetime >= '2011-06-13 00:00:00' AND activated_datetime <= '2011-06-21 23:59:59' AND clerk_code LIKE 'S%' GROUP BY clerk_id
Please check and see if it returns the same thing and if performance improves
SELECT clerk_id, COUNT(*) AS num
FROM `contracts`
WHERE EXISTS (
SELECT *
FROM contract_connections
WHERE `type` <>4 AND `type` <>6 AND `cancelled` =0 AND `ebill` <> '' AND activated_datetime >= '2011-06-13 00:00:00' AND activated_datetime <= '2011-06-21 23:59:59' AND clerk_code LIKE 'S%'
AND contract_connections ON contract_connections.contract_id = contracts.id
)
GROUP BY clerk_id
In case you have an index on the type column you could benefit from it changing your WHERE clause from
WHERE type <>4 AND type <>6
To
WHERE (type<4 OR type=5 OR type>6)
Also remove
activated_datetime > '0000-00-00 00:00:00'
Since you already have
activated_datetime >= '2011-06-13 00:00:00'

Something wrong with my mySQL query

SELECT t.id, t.active, t.off, t.duration, t.user
FROM table t
WHERE t.active = '0000-00-00 00:00:00'
OR t.duration != '0'
AND t.user = '1'
AND t.off = '0000-00-00 00:00:00'
LIMIT 0 , 30
Basically it's ignoring the t.off part, whats wrong?
Thank you =)
(the query was edited for an example purpose, the real query is similar to this but with other table names, etc)
== [ Update ] ==
SELECT t.active, t.off, t.duration, t.user
FROM table t
WHERE (
t.active = '0000-00-00 00:00:00'
OR t.duration != '0'
)
AND t.user = '1'
AND t.off = '0000-00-00 00:00:00'
LIMIT 0 , 30
UNION ALL
SELECT c.active, c.off, c.duration, c.user
FROM chair c
WHERE (
c.active = '0000-00-00 00:00:00'
OR c.duration != '0'
)
AND c.user = '1'
AND c.off = '0000-00-00 00:00:00'
You should use parenthesis, to group conditions (and / or), to make sure they are evaluated in the order you want.
For example, do you want to following :
SELECT t.id, t.active, t.off, t.duration, t.user
FROM table t
WHERE t.active = '0000-00-00 00:00:00'
OR (
t.duration != '0'
AND t.user = '1'
AND t.off = '0000-00-00 00:00:00'
)
LIMIT 0 , 30
Or the following :
SELECT t.id, t.active, t.off, t.duration, t.user
FROM table t
WHERE (
t.active = '0000-00-00 00:00:00'
OR t.duration != '0'
)
AND t.user = '1'
AND t.off = '0000-00-00 00:00:00'
LIMIT 0 , 30
Or maybe something else ?
Using parenthesis will make your query easier to read -- and will help making sure the conditions are evaluated properly.