Rewrite query with only 1 group by clause - mysql

This bellow query will result the post wise sum of like
SELECT
tblPost.Post,
SUM(tblPost.LikeCount),
CASE WHEN tblPost.Time
BETWEEN (SELECT
CONVERT(VARCHAR(10),
DATEADD(DD,DATEDIFF(DD 0,GETDATE()),-60),120)) AND CONVERT(date,GETUTCDATE())
THEN 'Last 60 Days'
ELSE 'More Than 1 Year'
END AS"date type"
FROM tblPost
INNER JOIN tblProfile ON (tblProfile.ID=tblPost.UID)
INNER JOIN tblWatchList ON (tblWatchList.ID=tblProfile.UID)
WHERE dbo.tblPost.Time BETWEEN (SELECT
CONVERT(VARCHAR(10),
DATEADD(DD,DATEDIFF(DD,0,GETDATE()), -60),120))AND CONVERT(date,GETUTCDATE())
GROUP BY tblPost.Post,tblPost.Time
This is my query and it is working fine but I want to rewrite this. How can I describe it here... in my query I am having two GROUP BY clauses (tblPost.Post,tblPost.Time) and exactly here I'm getting a problem. I want to rewrite this query such as a way that I can group my result only by tblPost.Post
Please help me.

Your WHERE clause already eliminates the two options you've presented for tblPost.Time - you explicitly state you're only ever going to retrieve "Last 60 days" so why are you bothering to have a whole CASE statement in the query?
And you're joining tables that aren't even represented. So start by cleaning your query up, use some aliases, and drop what you don't need:
SELECT P.Post, SUM(P.LikeCount)
FROM dbo.tblPost P
WHERE P.Time BETWEEN (SELECT CONVERT(VARCHAR(10), DATEADD(DD,DATEDIFF(DD,0,GETDATE()), -60),120)) AND CONVERT(date, GETUTCDATE())
GROUP BY P.Post

Related

mySql Query running super slow

I have seen a few post's regarding slow queries but none had the answer I'm hoping for.
I've been staring at this query for ages and for some reason cant see whats making this so damn slow dates such as 2022-01-01 > 2022-12-21 even taking 80 seconds....
So here is the query
SELECT
accounts.first_name,
accounts.last_name,
accounts.email,
(
SELECT
COUNT(ID)
FROM
customer_migration_details
WHERE
date_opened BETWEEN '2022-01-01' AND '2022-12-31' AND customer_migration_details.Assigned_to = accounts.email GROUP BY `accounts`.`email` LIMIT 1
) AS 'New Customers'
FROM
customer_migration_details
RIGHT JOIN accounts ON customer_migration_details.Assigned_to = accounts.email
WHERE
date_opened BETWEEN '2022-01-01' AND '2022-12-31' AND customer_migration_details.Assigned_to = accounts.email AND accounts.role LIKE '%Sales%'
GROUP BY
`accounts`.`email`
Heres the results
but here is the annoying part.
Showing rows 0 - 7 (8 total, Query took 109.5797 seconds.)
Theres got to be something im missing in the subquery maybe thats causing this to take so long.
acc: INDEX(email)
cmd: INDEX(Assigned_to, date_opened)
Having GROUP BY acc.email in the subquery seems wrong. And it may be unnecessary in the outer query.
Do not say COUNT(x) unless you need to avoid counting rows with x IS NULL. Instead, say simply COUNT(*).
If date_opened is a DATETIME, then you have excluded all but one second of New Years Eve.
LIKE with an initial wildcard is a performance problem. Are there multiple "roles" with "Sales" in them?
My brain gets scrambled when I see RIGHT JOIN. Can it be turned around to be a LEFT JOIN? Anyway, it seems to be an INNER JOIN.
Please provide EXPLAIN SELECT ...
Use a JOIN with GROUP BY or use a correlated sub-query, but not both at the same time.
SELECT
accounts.first_name,
accounts.last_name,
accounts.email,
COUNT(customer_migration_details.id) AS new_customers
FROM
accounts
LEFT JOIN
customer_migration_details
ON customer_migration_details.assigned_to = accounts.email
AND customer_migration_details.date_opened BETWEEN '2022-01-01' AND '2022-12-31'
WHERE
accounts.role LIKE '%Sales%'
GROUP BY
accounts.email
Or...
SELECT
accounts.first_name,
accounts.last_name,
accounts.email,
(
SELECT
COUNT(ID)
FROM
customer_migration_details
WHERE
date_opened BETWEEN '2022-01-01' AND '2022-12-31'
AND assigned_to = accounts.email
)
AS new_customers
FROM
accounts
WHERE
accounts.role LIKE '%Sales%'
Notes:
It's bad practice to put spaces, etc, in column names, so I changed New Customers to new_customers.
LIKE '%Sales%' can't use an index, so will scan each and every account row.

How to total "AS" column in mysql query?

I need SUM of AS column "profit"and "purch_price". I tried few things group by stock.id etc but it is not giving me same answer. please let me know how to take their sum.
SELECT
jobc_consumble.Stock_id,
jobc_consumble.issued_qty,
jobc_consumble.total,
p_purch_stock.Price,
p_purch_stock.Price * jobc_consumble.issued_qty AS "purch_price",
jobc_consumble.total -(SELECT purch_price) AS "profit"
FROM
jobc_consumble
INNER JOIN p_purch_stock ON jobc_consumble.stock_id = p_purch_stock.stock_id
WHERE
DATE_FORMAT(
jobc_consumble.issue_time,
'%Y-%m-%d'
) BETWEEN '2018-07-03' AND '2018-07-03'
Output should be like so :
I want sum of last two columns.
sum of PROFIT: 1105
sum of purch_price: 11000
Just repeat the logic in your SELECT clause:
SELECT
j.Stock_id,
j.issued_qty,
j.total,
p.Price,
p.Price * j.issued_qty AS purch_price,
j.total - (p.Price * j.issued_qty) AS profit
FROM jobc_consumble j
INNER JOIN p_purch_stock p
ON j.stock_id = p.stock_id
WHERE
DATE_FORMAT(j.issue_time, '%Y-%m-%d') = '2018-07-03';
For some notes, the only alternative to repeating the purchase price logic would be to wrap your current query as a subquery and reuse the alias. But, that would probably not be too performant. Your DATE_FORMAT expression does not make much sense, because the range is just a single day. If you don't like my version, then let us know what logic you really intended.

Mysql - comparing two strings in the same table on different dates

Relevant table structure is:
id(INT), reference_id(INT), status(VARCHAR(20)), date(TIMESTAMP)
This record is updated once per day.
Problem:
I want to display each record where the status field, which is static most of the time, is different to the one on the preceeding day, thus being able to show the date a status changed and display a history.
How?
Pseudo:
Show * where status for today != status for yesterday
Early logic, but my limited knowledge of mysql is causing me to hit a wall.
SELECT * from table_name WHERE DATE(date) = CURDATE()
UNION
SELECT table_name.status AS yesterday_status WHERE DATE(date) = CURDATE() - 1
I was then going to compare them both in perl, which is not so efficient so I'm hoping somebody can share some enlightenment...
Here is my approach. It is not exactly what you were asking for, but if maybe you will like my solution.
http://sqlfiddle.com/#!9/896b4/7
SELECT
today.*,
yesterday.*
FROM t_status today
LEFT JOIN t_status yesterday
ON DATE(yesterday.date)<DATE(today.date)
AND yesterday.reference_id = today.reference_id
AND yesterday.status != today.status
WHERE DATE(today.date) = CURDATE()
ORDER BY yesterday.date DESC
LIMIT 1
;
UPDATE Or probably I misunderstood your goal, and you need only compare yesterdays status, not all past statuses. If so you can try this INNER JOIN:
http://sqlfiddle.com/#!9/dd61f1/4
SELECT
today.*,
yesterday.*
FROM t_status today
INNER JOIN t_status yesterday
ON DATE_ADD(CURDATE(),INTERVAL -1 DAY) = DATE(yesterday.date)
AND yesterday.reference_id = today.reference_id
AND yesterday.status != today.status
WHERE DATE(today.date) = CURDATE();
You are welcome if any questions.
The below query shows the records along with the previous day's record (I assumed that reference_id is also a join citeria, if not, just remove it)
select t1.*, t2.* from table t1
left join table t2 on t1.reference_id=t2.reference_id and date(t1.date)-1=date(t2.date)
You can even filter it further to display only those pairs, where the previous day's status is different (note that the join changes from left to inner, since if there is no previous day's record, that's not a change is status):
select t1.*, t2.* from table t1
inner join table t2 on t1.reference_id=t2.reference_id and date(t1.date)-1=date(t2.date) and t1.status<>t2.status
I think query should be like
select * from tablename where status <> (select * from tablename where date=Sysdate-1)
Sysdate is use for System date.

Query Is Not Summing As I Need

I am trying to write a CTE Query and I am way before a "New" title for CTE Queries. But I feel I am fairly close to getting the end game that I am after. My query works perfect until I throw in the CTE and even after including the CTE it still works perfect just gives each individual instance as opposed to the SUM like I need. What should I alter in my syntax so that the query only produces the SUM as I need?
;With CTE
As
(
SELECT
BadgeNum
,NameOnFile
,SUM((CONVERT(decimal(18,6),pyrll.hoursworked))) AS [Hours]
FROM
masterpayroll pyrll
Group By
BadgeNum,NameOnFile
)
SELECT
,SUM(pyrll.[Hours]) As [Hours Worked This Week]
,pyrll.NameOnFile As [Employee Name]
,COUNT(case when pf.arrest_status in ('Final', 'Complete',) And pf.supervisorSignoff IS NOT NULL THEN pf.ID else null end)
,COUNT(case when pf.arrest_status in ('Pending', 'Incomplete', 'On Hold') THEN pf.ID else null end)
FROM personelFiles pf
INNER JOIN CTE pyrll
ON pf.ID = pyrll.BadgeNum
WHERE pf.officerName Like 'Gat%'
GROUP BY pyrll.[Employee Name], pyrll.[Hours Worked This Week]
EDIT ---Top Data Set is what is returned from query - bottom data set is what I want to see returned.
EDIT # 2 - If their is a better way to write the query to still produce the desired result of the 2nd data set in my image below I am up for that as well!
You have aggregate column alias name in the group by, you need only the employee name
Change your group by clause from
GROUP BY pyrll.[Employee Name], pyrll.[Hours Worked This Week]
To
GROUP BY pyrll.NameOnFile

Using a case/if in the where clause SQL

So I have a list of items organized by date in two different categories, when switching the categories I sometimes run into an error that does not let the item go into the correct placement. The thing that is messing up the query is what I want to place in a case/if statement becuase it is only needed if there is an item with the same date, anyother time it throws off the whole query. Here is what I have, granted i know that that case does not work where it is or how it is, please work with me.
SELECT CASE WHEN COUNT(*)=0 THEN (SELECT MAX(Rotate)+1 FROM Table1 WHERE Vol=1)
ELSE MIN(o.Rotate) END as nRotate FROM Table1 o INNER JOIN Table2 s ON o.SID=s.ID
WHERE s.Date >='7/30/2004' And s.ID<>100 And o.Vol=1 and
Case s.DATE
When '7/30/2004' then s.Sales>'Doe, Jane'
End
You don't need case:
WHERE s.Date >='2004-07-30' And s.ID <> 100 And o.Vol = 1 and
(s.date <> '2004-07-30' or s.Sales > 'Doe, Jane')