extract last week data (and not last 7 days) - mysql

I have data with below format.
id - autoincrement
myDate - timestamp
What I want to extract is get ids of for the last week.
Note By last week, I meant from Sat - Thu and not last 7 days. Considering current date (12-Feb-2013), for me, last week would be 2-Feb-2013 to 8-Feb-2013.
I know you would say, week starts from Sunday, but as I am working in Arab countries, here Friday is OFF and work starts from Saturday.
I know for last 7 days it would be just below code
BETWEEN NOW() and DATE_SUB(NOW(), INTERVAL 7 DAY)
Data at sqlfiddle

Can you try below method to compute the desired result:
SELECT *,WEEKOFYEAR(dt),DAYOFWEEK(dt),DAYNAME(dt), DAYOFWEEK(NOW()),WEEKOFYEAR(NOW())
FROM tab1
WHERE 1
AND
(
(DAYOFWEEK(NOW()) = 1 OR DAYOFWEEK(NOW()) = 6 OR DAYOFWEEK(NOW()) = 7)
AND
WEEKOFYEAR(dt) = WEEKOFYEAR(NOW()) AND DAYOFWEEK(dt) < 6
)
OR
(
(DAYOFWEEK(NOW()) = 2 OR DAYOFWEEK(NOW()) = 3 OR DAYOFWEEK(NOW()) = 4
OR DAYOFWEEK(NOW()) = 5)
AND
(
(
(WEEKOFYEAR(dt) = WEEKOFYEAR(NOW())-2 AND DAYOFWEEK(dt) >= 6)
OR
(WEEKOFYEAR(dt) = WEEKOFYEAR(NOW())-1 AND DAYOFWEEK(dt) > 1 AND DAYOFWEEK(dt) < 6)
)
)
);
I know this is not the smartest way, but based on this you might get hint for better solution.
Demo at sqlfiddle

Related

How to select records but exclude if one type is outside a subquery?

We have multiple invStatus values (1-10) and want to exclude only one status type (1) BUT only those of that type that are a older than X number of days. So all records will show but NOT those who's invStatus = 1 and is older than X days. invStatus = 1 and younger than X days will be included in the recordset.
Do I select all records generically, then in a subquery filter those of status = 1 that are older than X days?
The query below uses NOT IN in an attempt to select those records to exclude but it is not working and also seems to be inefficient as it takes a couple seconds to execute.
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND invStatus NOT IN (SELECT invId from tblhouseinfo WHERE invStatus = 1
AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
I could filter the results with PHP on the page level but this also seems less than efficient and would prefer to perform this task using the best practices.
UPDATE:
There are a total of 155 rows.
All tblhouseinfo.Update_date (timestamp) values are "2017-09-06 10:53:17" (Aug 9th) accept three I changed for testing to "2017-07-06 10:53:17
" (July 6th)
Utilizing the suggestion for :
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date > CURRENT_DATE() - INTERVAL 10 DAY )
60 records are excluded not the expected 3.
"2017-08-28" is the current result from CURRENT_DATE() - INTERVAL 10 DAY which should be within the 10 day range to select "2017-09-06 10:53:17" and only exclude the three records that are "2017-07-06 10:53:17"
FINAL WORKING SOLUTION/Query:
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
You don't need to select invID from the other table if you know you never want the ID #1 (invStatus 1). But you can also throw in an AND statement for the # of days.
I always use timestamps (in UNIX) for recording data entry / modification.
AND (timestamp >= beginTimestamp AND timeStamp <= endTimestamp)

MySQL date between last monday and the next sunday

i'm looking to find all records that have a booking date between the previous monday and the next sunday in MySQL.
So far I have:
SELECT firstname
, lastname
, sessions
, (SELECT COUNT(memberid)
FROM bookings
WHERE m.memberid = b.memberid
and b.date between lastMonday and nextSunday) as sessionsused
from members
I'm looking what to substitute into the lastmonday and nextsunday
Any help is much appreciated!
MySQL's YEARWEEK() function selects a unique value for each week that you can use for comparison. It takes a second parameter which specifies whether weeks start on Sunday (0) or Monday (1).
SELECT COUNT(memberid)
FROM bookings
WHERE m.memberid = b.memberid
AND YEARWEEK(b.date, 1) = YEARWEEK(NOW(), 1);
This will always select rows where b.date is in the current week. For a specific week in the past, change NOW() for whatever date expression you require.
For the more generic case where your week does not start on a Sunday or a Monday, you will need some slightly more complicated logic. Here you substitute #weekday with the day on which your weeks begin, 2 = Tues, 3 = Wed, 4 = Thu, 5 = Fri, 6 = Sat.
SELECT COUNT(memberid)
FROM bookings
WHERE m.memberid = b.memberid
AND DATE(b.date)
BETWEEN DATE_SUB(DATE(NOW()), INTERVAL (WEEKDAY(NOW()) - #weekday + 7) % 7 DAY)
AND DATE_ADD(DATE(NOW()), INTERVAL 6 - (WEEKDAY(NOW()) - #weekday + 7) % 7 DAY);

Percentage change from previous row when multiple rows have the same date?

I have a query that calculates ratios and returns them for each hour and server on a given day:
SELECT a.day,
a.hour,
Sum(a.gemspurchased),
Sum(b.gems),
Sum(b.shadowgems),
( Sum(b.gems) / Sum(a.gemspurchased) ) AS GemRatio,
( Sum(b.shadowgems) / Sum(a.gemspurchased) ) AS ShadowGemRatio
FROM (SELECT Date(Date_sub(createddate, INTERVAL 7 hour)) AS day,
Hour(Date_sub(createddate, INTERVAL 7 hour)) AS hour,
serverid,
Sum(gems) AS GemsPurchased
FROM dollartransactions
WHERE Date(Date_sub(createddate, INTERVAL 7 hour)) BETWEEN
Curdate() - INTERVAL 14 day AND Curdate()
GROUP BY 1,
2,
3) a,
/*Gems recorded from DollarTransactions Table after purchasing gem package*/
(SELECT Date(Date_sub(createddate, INTERVAL 7 hour)) AS day,
Hour(Date_sub(createddate, INTERVAL 7 hour)) AS hour,
serverid,
Sum(acceptedamount) AS Gems,
Sum(acceptedshadowamount) AS ShadowGems
FROM gemtransactions
WHERE Date(Date_sub(createddate, INTERVAL 7 hour)) BETWEEN
Curdate() - INTERVAL 14 day AND Curdate()
AND transactiontype IN ( 990, 2 )
AND fullfilled = 1
AND gemtransactionid >= 130000000
GROUP BY 1,
2,
3) b
/*Gems & Shadow Gems spent, recorded from GemTransactions Table */
WHERE a.day = b.day
AND a.serverid = b.serverid
GROUP BY 1,
2
This code returns the component parts of the ratios, as well as the ratios themselves (which are sometimes null):
day hour sum(a.GemsPurchased) sum(b.Gems) sum(b.ShadowGems) GemRatio ShadowGemRatio
9/5/2014 0 472875 465499 60766 0.9844 0.1285
9/5/2014 1 350960 371092 45408 1.0574 0.1294
9/5/2014 2 472985 509618 58329 1.0775 0.1233
9/5/2014 3 1023905 629310 71017 0.6146 0.0694
9/5/2014 4 1273170 628697 74896 0.4938 0.0588
9/5/2014 5 998920 637709 64145 0.6384 0.0642
9/5/2014 6 876470 651451 68977 0.7433 0.0787
9/5/2014 7 669100 667217 81599 0.9972 0.122
What I'd like to do is create an 8th and 9th column which calculate the % change from previous row for both GemRatio and ShadowGemRatio. I've seen other threads here on how to do this for specific queries, but I couldn't get it to work for my particular MySQL query...
Ok first create a view for that query. Let's call it v1:
CREATE VIEW v1 AS SELECT YOUR QUERY HERE;
Now here is the query to have the ratios. I assumed a day has 24 hours. The first row ratio change will be zero.
select now.*,
CASE
WHEN yesterday.gemRatio is null THEN 0
ELSE 100*(now.gemRatio-yesterday.gemRatio)/yesterday.gemRatio
END as gemChange,
CASE
WHEN yesterday.ShadowGemRatio is null THEN 0
ELSE 100*(now.ShadowGemRatio-yesterday.ShadowGemRatio)/yesterday.ShadowGemRatio
END as shadowGemChange
from v1 now left outer join v1 yesterday on
((now.day = yesterday.day && now.hour = yesterday.hour+1) ||
(DATEDIFF(now.day,yesterday.day) = 1 && now.hour = 0 && yesterday.hour=23))

MySQL: search orders made since yesterday 3pm till today 4pm

I have table ORDERS where is stored data about orders with their status and the date of order. I would like to search all orders with specified status and which was made yesterday after 3pm untill today 4pm. The query will run in different times (10am, 3pm, 5 pm... regardless).
So on example: if I run the query today (13.05.2014) I would like to get all orders made from 2014-12-05 15:00:00 untill 13-05-2015 16:00:00
The date is stored in format: YYYY-MM-DD HH:MM:SS
What I got is:
select *
from orders
where status = 'new'
and (
(
date_add(created_at, INTERVAL 1 day) = CURRENT_DATE()
and hour(created_at) >= 15
) /*1*/
or (
date(created_at) = CURRENT_DATE()
and hour(created_at) <= 16
) /*2*/
)
And I get only orders made today - like only the 2nd condition was taken into account.
I prefer not to use created >= '2014-05-12 16:00:00' (I will not use this query, someone else will).
When you add an interval of 1 day to the date/time, you still keep the time component. Use date() for the first condition:
where status = 'new' and
((date(date_add(created_at, INTERVAL 1 day)) = CURRENT_DATE() and
hour(created_at) >= 15
) /*1*/ or
(date(created_at) = CURRENT_DATE() and
hour(created_at) <= 16
) /*2*/
)
And alternative method is:
where status = 'new' and
(created_at >= date_add(CURRENT_DATE(), interval 15-24 hour) and
created_at <= date_add(CURRENT_DATE(), interval 16 hour)
)
The advantage of this approach is that all functions are moved to CURRENT_DATE(). This would allow MYSQL to take advantage of an index on created_at.

Find 2 Business Days

I have a Calendar table. I would like get 2 business before Today's Date while skipping Holidays and weekeends.
For example:
Example 1: New years 2013 falls on a Tuesday. If it was Thursday (1/3), then my starting date would be Monday (12/31).
Example 2: If it was Monday (12/31), then my starting date would be Thursday (12/27).
My Clandar table as been prepopulated with 30 years worth of dates and have flags to determine which ones are weekend and hollidays. The table has these fields:
dt: Date and time for 30 years
Y: year
D: Day
M: Month
Isholiday: (Is a holiday are not, flagged with 0 for "no" and 1 for "Yes")
IsWeekday: (Is a weekday? Flagged with 0 for "no" and 1 for "Yes"
HolidayDescritption: Holiday Names
Please help.
This is what you want :
select top 1 *
from ( select *
from Calendar
where IsHoliday = 0
and IsWeekday = 1
and dt between DateAdd( Day, -6, GetDate ) and GetDate()
) tmpCalendar
where dt <= DateAdd( Day, -2, GetDate() )
order by dt desc
Make sure to replace * with only the fields that you want.
Try this one:
SELECT dt FROM
(
SELECT dt, ROW_NUMBER() OVER (ORDER BY dt DESC) AS R
FROM
Calendar
WHERE
IsHoliday = 0
AND IsWeekday = 1
AND dt < GETDATE()
) T
WHERE R = 2