How to add new column in select statement - mysql

i want to add new column in my select statement
SELECT name,line,style,operation,
7to8am,8to9am,9to10am,10to11am,11to12am,
1to2pm,2to3pm,3to4pm,4to5pm,5to6pm,6to7pm,7to8pm,8to9pm,9to10pm,10to11pm,11to12pm,
sum(7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm
+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+
8to9pm+9to10pm+10to11pm+11to12pm) as DailyTotal,id from new_hourly GROUP By line
i want to add a new column that will show sum of DailyTotal that the day is today
This is my sql backup file http://www.uploadmb.com/dw.php?id=1446536983
Please help me! thank you so much!

So you want one additional columns that adds only lines where datee equals current date?
I'd go for case-when expression in this case:
coalesce(
sum(
case
when datee = CURDATE()
then 7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+8to9pm+9to10pm+10to11pm+11to12pm
else null
end
)
,0) as TodaysTotal
That's summing up only those rows where column datee is curdate() and returning 0 if no rows at all are present for today.
Full SQL:
SELECT name,line,style,operation,
7to8am,8to9am,9to10am,10to11am,11to12am,
1to2pm,2to3pm,3to4pm,4to5pm,5to6pm,6to7pm,7to8pm,8to9pm,9to10pm,10to11pm,11to12pm,
sum(7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm
+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+
8to9pm+9to10pm+10to11pm+11to12pm) as DailyTotal,
coalesce(
sum(
case
when datee = CURDATE()
then 7to8am+8to9am+9to10am+10to11am+11to12am+1to2pm+2to3pm+3to4pm+4to5pm+5to6pm+6to7pm+7to8pm+8to9pm+9to10pm+10to11pm+11to12pm
else null
end
)
,0) as TodaysTotal
,id from new_hourly GROUP By line

Related

SQL - empty result set for checking if date is past the current date

I have a query in MariaDB 10.3 database where there is a field called "expiration_date" that stores a unix timestamp, but if there is no data in the field the default is set to "0".
I'm trying to use a WHERE clause to check the current date against the expiration_date to filter out any records that are past the expiration_date. Below is what I have.
SELECT entry_id, title, (CASE WHEN expiration_date = "0" THEN CURDATE() + INTERVAL 1 DAY ELSE FROM_UNIXTIME(expiration_date, "%Y-%m-%d") END) AS expiration_date
FROM channel_titles
WHERE CURDATE() < expiration_date
This returns and empty result set... what am I missing?
There's a very simple solution to this and it only requires you to change two things from your original query:
The first part is your column (CASE expression) alias - you should define your alias with something not similar to any of the column names present in the table. From your query, you have a column expiration_datein your table and you also set an alias for your CASE expression with expiration_date as well and since you're using WHERE, the query will definitely do the lookup based on your table expiration_date column instead of your CASE expression. Rename that alias to something like exp_date... but doing WHERE exp_date ... will return you an error. Refer to the second point below.
The second part is your WHERE - since you're doing lookup from a CASE expression (or perhaps custom generated value/column) with newly assigned alias of exp_date, you can't use it in WHERE.. well, unless you make the query as a subquery/derived table then do the WHERE outside.. but you don't need to. You only need to change WHERE to HAVING and you should be able to use the exp_date and get your result.
So, with those two changes, your query should be something like this:
SELECT entry_id, title,
(CASE WHEN expiration_date = "0" THEN CURDATE() + INTERVAL 1 DAY ELSE
FROM_UNIXTIME(expiration_date, "%Y-%m-%d") END) AS exp_date
FROM channel_titles
HAVING CURDATE() < exp_date;
demo fiddle
You're trying to use an alias of expiration_date from your CASE statement in your WHERE clause.
Two problems with this:
You cannot use column aliases in the WHERE clause. Refer to this post here.
WHERE happens before SELECT in the execution chain.
Your alias matches an actual column name in your table, so your
WHERE clause is not throwing an error regarding your alias, its
comparing the current date to the expiration_date column in the table,
thus, throwing off your expected result.
Solutions:
If you want to use the alias in your WHERE clause, there are a few options for you to force SQL to handle the SELECT before the WHERE clause.
You can use a subquery (or subselect) to force logical order of
operation by using parentheses:
SELECT
a.entry_id,
a.title,
a.expiration_date
FROM
(SELECT
entry_id,
title,
(CASE WHEN expiration_date = 0 THEN CURDATE() + INTERVAL 1 DAY ELSE FROM_UNIXTIME(expiration_date, '%Y-%m-%d') END) AS expiration_date
FROM channel_titles
) a
WHERE CURDATE() < a.expiration_date
You can declare your alias in a Common Table Expression (CTE), then SELECT it FROM the CTE:
WITH cte AS (SELECT
entry_id,
title,
(CASE WHEN expiration_date = 0 THEN CURDATE() + INTERVAL 1 DAY ELSE FROM_UNIXTIME(expiration_date, '%Y-%m-%d') END) AS expiration_date
FROM channel_titles)
SELECT
entry_id,
title,
expiration_date
FROM cte
WHERE CURDATE() < expiration_date
You can disregard using your alias entirely in your WHERE clause and plug in the logic from your SELECT statement directly into your WHERE clause. However, this may appear redundant from a readability perspective; also, extra processing should be considered when using this approach as well, but if you have a small data set this method will work just fine:
SELECT
entry_id,
title,
(CASE WHEN expiration_date = 0 THEN CURDATE() + INTERVAL 1 DAY ELSE FROM_UNIXTIME(expiration_date, '%Y-%m-%d') END) AS expiration_date
FROM channel_titles
WHERE CURDATE() < (CASE WHEN expiration_date = 0 THEN CURDATE() + INTERVAL 1 DAY ELSE FROM_UNIXTIME(expiration_date, '%Y-%m-%d') END)
Input:
entry_id
title
expiration_date
expiration_date_date
1
test1
1695513600
2023-09-24
2
test2
0
2022-09-15
3
test3
1662768000
2022-09-10
Output:
entry_id
title
expiration_date
1
test1
2023-09-24
2
test2
2022-09-15
db<>fiddle here.

condition in SELECT in mysql

I have a query that looks like this
SELECT customer, totalvolume
FROM orders
WHERE deliverydate BETWEEN '2020-01-01' AND CURDATE()
Is there any way to select totalvolume for specific date range and make it a separate column?
So for example, I already have totalvolume. I'd like to also add totalvolume for the previous month as a separate column (totalvolume where deliverydate BETWEEN '2020-08-01' AND '2020-08-31'). Is there a function for that?
Simply use 2 table copies:
SELECT t1.customer, t1.totalvolume, t2.totalvolume previousvolume
FROM orders t1
LEFT JOIN orders t2 ON t1.customer = t2.customer
AND t1.deliverydate = t2.deliverydate + INTERVAL 1 MONTH
WHERE t1.deliverydate BETWEEN '2020-08-01' AND '2020-08-31';
You can do it with case/when construct in your columns and just expand your WHERE clause. Sometimes I would do it by having a secondary #variables to simplify my clauses. Something like
SELECT
o.customer,
sum( case when o.deliveryDate < #beginOfMonth
then o.TotalVolume else 0 end ) PriorMonthVolume,
sum( case when o.deliveryDate >= #beginOfMonth
then o.TotalVolume else 0 end ) ThisMonthVolume,
sum( o.totalvolume ) TwoMonthsVolume
FROM
( select #myToday := date(curdate()),
#beginOfMonth := date_sub( #myToday, interval dayOfMonth( #myToday ) -1 day ),
#beginLastMonth := date_sub( #beginOfMonth, interval 1 month ) ) SqlVars,
orders o
WHERE
o.deliverydate >= #beginLastMonth
group by
o.customer
To start, the "from" clause of the query alias "SqlVars" will dynamically create 3 variables and return a single row for that set. With no JOIN condition, is always a 1:1 ratio for everything in the orders table. Nice thing, you don't have to pre-declare variables and the #variables are available for the query.
By querying for all records on or after the beginning of the LAST month, you get all records for both months in question. The sum( case/when ) can now use those variables as the demarcation point for the respective volume totals.
I know you mentioned this was a simplified query, but masking that might not be a perfect answer to what you need, but may help you look at it from a different querying perspective.

Why i get Null values in my second counter using case statement

The first case statement i got the correct result but in the second one
Why i got an NULL result Where my second case statement the counter = 2
this is the result i have an image
Query Result that i got Null data in second statement when i grouped by on my date
SELECT DISTINCT date,log,
CASE
WHEN note = 'HOLIDAY' AND counter = 1
THEN 'HOLIDAY'
END note1,
CASE
WHEN note = 'HOLIDAY' AND counter = 2
THEN 'HOLIDAY'
END note2,
FROM timesheet
WHERE timesheet.empid='40' AND date <= CURDATE() AND YEAR(date)= YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY date
ORDER BY date DESC;
You're using GROUP BY wrong. The rule is that each column in your SELECT clause is either also in your GROUP BY clause or an aggregate function (like count, min, max, avg) must be applied to it.
When you don't follow this rule, a random row for each group is displayed. In your case, when you really have data with note = 'HOLIDAY' AND counter = 2, the rows for the group might look like this
NULL
HOLIDAY
NULL
NULL
but after collapsing (when it's outputted by the select), just the first row is displayed, therefore the NULL value.
Try it like this:
SELECT date,
MIN(log), /*or maybe you want to group by this column, too? */
MAX(CASE
WHEN note = 'HOLIDAY' AND counter = 1
THEN 'HOLIDAY'
END) note1,
MAX(CASE
WHEN note = 'HOLIDAY' AND counter = 2
THEN 'HOLIDAY'
END) note2,
FROM timesheet
WHERE timesheet.empid='40' AND date <= CURDATE() AND YEAR(date)= YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY date
ORDER BY date DESC;
Also note, that I removed the DISTINCT. Your GROUP BY already does that.

Multiple COUNT() conditions for values on either side of a range

I currently have a query that finds all rows (with status=0) that have occurred before now:
SELECT id, COUNT(1) FROM tbl WHERE status = 0 AND date < UNIX_TIMESTAMP() GROUP BY id;
However, now I'd also like to be able to retrieve the values on the other side of this--i.e., I want to get all dates available after and before now, as two distinct values.
Is there any way to optimize this besides simply running two separate queries?
SELECT id
, SUM(date < UNIX_TIMESTAMP()) AS BeforeNow
, SUM(date > UNIX_TIMESTAMP()) AS AfterNow
FROM tbl
WHERE status = 0
GROUP BY id;
date < UNIX_TIMESTAMP() is a boolean expression, which equates to 1 or 0. The SUM of the expression is equal to the amount of times it was true, or its count.
You can do a conditional count.
SELECT id,
COUNT(CASE WHEN date < UNIX_TIMESTAMP() THEN 1 ELSE null END ) ,
COUNT(CASE WHEN date > UNIX_TIMESTAMP() THEN 1 ELSE null END )
FROM tbl GROUP BY id

Next closest date and time in MySQL

Inside of my Auctions table, I have a column called Auction_StartDate. The value of a row is like this: 2012-10-27 13:45:30.
I need a query that will return the next closest date and time after that. So if the next Auction_StartDate is 2012-10-27 18:30:00, it should return that before the date turns to 2012-10-28.
If you mean to do this for every row, try this:
SELECT a1.id,
(SELECT MIN(a2.Auction_StartDate)
FROM Auctions a2
WHERE a2.Auction_StartDate > a1.Auction_StartDate) AS nextStartDate
FROM Auctions a1
You can use MIN to find the closest value without using LIMIT and ORDER BY clause.
SELECT MIN(DATE(Auction_StartDate)) closestDate
FROM Auctions
WHERE DATE(Auction_StartDate) > '2012-10-27'
SQLfiddle Demo
May be this one helps
SELECT DATE(Auction_StartDate) closestDate
FROM Auctions
WHERE DATE(Auction_StartDate) > '2012-10-27'
order by Auction_StartDate ASC
limit 1
SELECT (case when Hour(StartDate)>=12 then DATE_ADD(StartDate,
INTERVAL 1 DAY) else StartDate end) as 'date' FROM table
------------------------------
pleaes add your column name where is static date :
est on : http://sqlfiddle.com/#!2/b8435/19
SELECT (case when Hour(StartDate )>=12 then
DATE_FORMAT( DATE_ADD(StartDate ,INTERVAL 1 DAY), '%Y-%m-%d')
else DATE_FORMAT(StartDate , '%Y-%m-%d') end) as 'date' from tabel