I have a problem that i cant solve with a SQL query for MySQL.
First table "content"
ID / Title / Author / Curated / Created
Next table "whitelist"
ID / Author / Weight
What i want the SQL to do is SELECT all content WHERE content.created >= UNIX_TIMESTAMP(DATE_SUB(now(), INTERVAL 14 day)) Also i what to order the Author random of the weight so the author with a high weight will show up more than a lower. As for now i am using this function ORDER BY -LOG(RAND(1337)) / whitelist.weight ASC. And finally i want every other row to be curated and the next one not.
So the result would be something like this.
ID Title Author Curated Created
3 My Home1 Krister 1 2015-01-20
13 My Home14 Krister 0 2015-01-20
33 My Home8 Eva 1 2015-01-15
34 My Home11 Krister 0 2015-01-01
43 My Home18 Eva 1 2015-01-01
What i have tried...
SELECT *
FROM (
SELECT `content`.*, IF(`content`.`curated`=0, #mr:=#mr+1, #fr:=#fr+1) AS cur
FROM `content` INNER JOIN `whitelist` ON `content`.`author` = `whitelist`.`author` , (SELECT #mr:=0, #fr:=0) initvars
WHERE
content.is_deleted = 0
AND content.created >= UNIX_TIMESTAMP(DATE_SUB(now(), INTERVAL 14 day))
) tmp
INNER JOIN whitelist ON tmp.author = whitelist.author
ORDER BY cur ASC LIMIT 5 OFFSET 0;
Try this:
SELECT * FROM content
JOIN whitelist ON content.Author = whitelist.Author
WHERE content.created >= UNIX_TIMESTAMP(DATE_SUB(now(), INTERVAL 14 day))
ORDER BY (RAND() * (SELECT MAX(Weight) FROM whitelist)) + Weight DESC
Now with curated:
SET #pos1=0;
SET #pos2=0;
SELECT * FROM
(
SELECT *, #pos1 := #pos1 + 1 pos FROM
(
SELECT Content.* FROM content
JOIN whitelist ON content.Author = whitelist.Author
WHERE curated = 0
AND content.created >= UNIX_TIMESTAMP(DATE_SUB(now(), INTERVAL 14 day))
ORDER BY (RAND() * (SELECT MAX(Weight) FROM whitelist)) + Weight
) s1
UNION
SELECT *, #pos2 := #pos2 + 1 pos FROM
(
SELECT Content.* FROM content
JOIN whitelist ON content.Author = whitelist.Author
WHERE curated = 1
AND content.created >= UNIX_TIMESTAMP(DATE_SUB(now(), INTERVAL 14 day))
ORDER BY (RAND() * (SELECT MAX(Weight) FROM whitelist)) + Weight
) s2
) t1
ORDER BY pos DESC, Curated
Related
+------------------------+--------+
| Invoice_id | due_date | amount |
+-------------+----------+--------+
| 20 |2020-01-18| 1250 |
+-------------+----------+--------+
| 21 |2020-01-15| 1335 |
+-------------+----------+--------+
Get all Records with date passed n days and its multiple serires
like below...
for example n=5
SELECT * FROM `invoices`
WHERE `due_date = DATE_ADD(CURDATE() + INTERVAL 5 days)
OR due_date = DATE_ADD(CURDATE() + INTERVAL 10 days)
OR due_date = DATE_ADD(CURDATE() + INTERVAL 15 days)`
but i want to make it universal for any n value
1 Way to achieve this is to generate a date range with 5 days difference and then join that with your table -
SELECT *
FROM `invoices` I
JOIN (SELECT a.Date
FROM (SELECT CURDATE() + INTERVAL (a.a + (10 * b.a) + (100 * c.a) ) * 5 DAY as Date
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as c
)a
WHERE a.Date <= (SELECT MAX(due_date) FROM `invoices`)
) ON I.due_date = a.Date
I have generated only 1000 rows here. If your table is too large then you may generate 10000 rows using 1 more cross-join.
WHERE (DATEDIFF(due_date, CURDATE) % 5) = 0
It'll select all the multiple of 5 before and after today...
You can create a variable and pass it into a prepared statement like below.
SET #dateinterval = n;
SET #preparedStatement = CONCAT("
SELECT * FROM `invoices`
WHERE `due_date` IN (
(CURDATE() + INTERVAL ",#dateinterval," day),
(CURDATE() + INTERVAL ",#dateinterval*2," day),
(CURDATE() + INTERVAL ",#dateinterval*3," day)
);
");
PREPARE SQLStatement FROM #preparedStatement;
EXECUTE SQLStatement;
DEALLOCATE PREPARE SQLStatement;
Provided u pass in 5 for the #dateinterval, the above statement will resolved as:
SELECT * FROM `invoices`
WHERE `due_date` IN (
(CURDATE() + INTERVAL 5 day),
(CURDATE() + INTERVAL 10 day),
(CURDATE() + INTERVAL 15 day)
);
If you are using MySQL version 8.0 or higher, here is another alternative -
WITH CTE (RN, ID, DUE_DATE, AMT) AS(
SELECT *, ROW_NUMBER() OVER(ORDER BY due_date) RN FROM Invoices
WHERE due_date >=CURDATE()
)
SELECT * FROM CTE WHERE RN%5=0
I'm trying to summarize the calories of activities per day for a specific user for the last 7 days (actual day is 7th day). There are tables user and activities and the mapping table user_activities.
The following example is for the user with id=1;
Sum up calories each day last 7 days (this day 7th day) */
SELECT
DATE(a.end_time), SUM(a.calories)
FROM
activities a
JOIN
user_activities uc ON uc.activity_id = a.id
WHERE
uc.user_id = 1
AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY
DATE(a.end_time) DESC
That query returns this result set:
2018-12-28 9600
2018-12-27 1200
2018-12-26 1200
2018-12-25 1200
2018-12-24 4800
2018-12-22 1200
Which is correct but now my problem is, as you can see in the list the 12-23-2018 is not listed because there are no activities on this date. Now I want to display
2018-12-23 0
instead of nothing.
How can I get the desired result?
Thanks for your help
I also tried with IFNULL and COALESCE but no luck so far
Sum up calories each day last 7 days (this day 7th day) */
SELECT
DATE(a.end_time), SUM(a.calories)
FROM
activities a
JOIN
user_activities uc ON uc.activity_id = a.id
WHERE
uc.user_id = 1
AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY
DATE(a.end_time) DESC
Result:
2018-12-28 9600
2018-12-27 1200
2018-12-26 1200
2018-12-25 1200
2018-12-24 4800
2018-12-22 1200
Expected result:
2018-12-28 9600
2018-12-27 1200
2018-12-26 1200
2018-12-25 1200
2018-12-24 4800
2018-12-23 0
2018-12-22 1200
Activities table:
If there's a chance your activities table doesn't have an activity listed on a particular day, then fa06's trick won't work out. A simple way to cover that case is to add some zero records on before you do your sum:
SELECT DATE(d), SUM(c)
FROM (
SELECT a.end_time as d, a.calories as c
FROM activities a
JOIN user_activities uc ON uc.activity_id = a.id
WHERE uc.user_id = 1
AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
UNION ALL
SELECT CURRENT_DATE, 0
UNION ALL
SELECT CURRENT_DATE - INTERVAL 1 DAY, 0
UNION ALL
SELECT CURRENT_DATE - INTERVAL 2 DAY, 0
UNION ALL
SELECT CURRENT_DATE - INTERVAL 3 DAY, 0
UNION ALL
SELECT CURRENT_DATE - INTERVAL 4 DAY, 0
UNION ALL
SELECT CURRENT_DATE - INTERVAL 5 DAY, 0
UNION ALL
SELECT CURRENT_DATE - INTERVAL 6 DAY, 0
) z
GROUP BY DATE(d)
fa06's method relies on there being one record every day in the activities table. It's a valid way to approach the problem, but you haven't been specific about what data these tables contain (hint: when posting a db question, do include sample data from each table)
With this method we do our lookup as normal, but we also generate 7 fake rows with dates from the last 7 days and a 0 calorie count. When added onto real calorie counts, these are fat free ;) and when there is no data for a particular day, these stand alone to provide the 0
If you want more days, consider moving to a row generating pattern. MySQL doesn't have row generators like other DBs, but the simplest trick is to create
variable, init it with 0 then increment and use it upon every row returned from a table with at least 30 rows:
SELECT CURRENT_DATE - INTERVAL (#row := #row + 1) DAY as dt, 0 as cal
FROM activities t, (SELECT #row := -1) r
LIMIT 30
The theory behind this is: the table has at least 30 rows, #row variable is inited to -1, and exists session-wide for the query. As rows are pulled out and returned, #row is incremented and then returned (so it's 0, 1, 2.. ) and this increasing count is used to subtract 0, 1, 2 etc days off of the current data, giving us a sequence of dates for the past 30 days
SELECT DATE(d), SUM(c)
FROM (
SELECT a.end_time as d, a.calories as c
FROM activities a
JOIN user_activities uc ON uc.activity_id = a.id
WHERE uc.user_id = 1
AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 29 DAY
UNION ALL
SELECT CURRENT_DATE - INTERVAL (#row := #row + 1) DAY as dt, 0 as cal
FROM activities t, (SELECT #row := -1) r
WHERE #row < 30
) z
GROUP BY DATE(d)
Note that I wasn't able to test either of these queries; the second might have some minor syntax error. If it turns out not to work, and the error is nontrivial/something you cant fix let me know.
Debugging:
Run each of these queries in isolation. I don't know how many rows this will produce:
SELECT a.end_time as d, a.calories as c
FROM activities a
JOIN user_activities uc ON uc.activity_id = a.id
WHERE uc.user_id = 1
AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 29 DAY
And this one should produce 30 rows. If it doesn't it will be because you didn't use a table with at least 30 rows:
SELECT CURRENT_DATE - INTERVAL (#row := #row + 1) DAY as dt, 0 as cal
FROM activities t, (SELECT #row := -1) r
LIMIT 30
Edit:
Fixed the bug with this - LIMIT was being applied after the union; this was giving undesired results
You can try below - using left join
SELECT DATE(a.end_time), SUM(a.calories)
FROM activities a
left JOIN user_activities uc ON uc.activity_id = a.id
Where uc.user_id = 1 AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY DATE(a.end_time) order by DATE(a.end_time) DESC
I'm trying it on my end and just updated the SUM(a.calories) to IF(SUM(a.calories) IS NULL, 0, SUM(a.calories))
Here you may try...
SELECT DATE(a.end_time), IF(SUM(a.calories) IS NULL, 0, SUM(a.calories))
FROM activities a
JOIN user_activities uc ON uc.activity_id = a.id
WHERE uc.user_id = 1
AND
DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY DATE(a.end_time) DESC
This query should to the trick :
the CTE dynamically generates a date range (this will go up to about 300 years ahead)
the result is LEFT JOINed with the activities and user_activities tables
the COALESCE function turns empty SUMs into 0 values
Query :
WITH v AS (
SELECT * FROM
(SELECT adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date FROM
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4) v
WHERE selected_date BETWEEN CURRENT_DATE - INTERVAL 6 DAY AND CURRENT_DATE
)
SELECT v.selected_date, COALESCE(SUM(a.calories), 0)
FROM
v
LEFT JOIN activities a on DATE(a.end_time) = v.selected_date
LEFT JOIN user_activities uc ON uc.activity_id = a.id AND uc.user_id = 1
GROUP BY DATE(a.end_time) DESC
ORDER BY v.selected_date
Query
UPDATE vcd_resorts AS resorts,
vcd_deals AS deals
SET resorts.rst_live_date = Date_add(Curdate(), INTERVAL 4 day),
deals.del_date = Date_add(Curdate(), INTERVAL 4 day)
WHERE 0 = (SELECT resort_id_count
FROM (SELECT Count(rst_id) AS resort_id_count
FROM vcd_resorts
WHERE rst_supersaver_resort = 1
AND rst_live_date BETWEEN Curdate() + 1 AND
Curdate() + 4)
temp)
AND resorts.rst_supersaver_resort = 1
AND resorts.rst_id = deals.del_resort_id
AND deals.del_supersaver_deal = 1
ORDER BY resorts.rst_live_date ASC
LIMIT 1
Error
#1221 - Incorrect usage of UPDATE and ORDER BY
what is wrong in this and any other way to do this
There is no sense of using ORDER BY in Update. Because the command updates all the matching orders no matter in what sequence.
Use Update command without ORDER BY clause as:
UPDATE vcd_resorts AS resorts,
vcd_deals AS deals
SET resorts.rst_live_date = Date_add(Curdate(), INTERVAL 4 day),
deals.del_date = Date_add(Curdate(), INTERVAL 4 day)
WHERE 0 = (SELECT resort_id_count
FROM (SELECT Count(rst_id) AS resort_id_count
FROM vcd_resorts
WHERE rst_supersaver_resort = 1
AND rst_live_date BETWEEN Curdate() + 1 AND
Curdate() + 4)
temp)
AND resorts.rst_supersaver_resort = 1
AND resorts.rst_id = deals.del_resort_id
AND deals.del_supersaver_deal = 1
LIMIT 1
i got solution of this question
UPDATE vcd_resorts AS resorts,
vcd_deals AS deals
SET resorts.rst_live_date = Date_add(Curdate(), INTERVAL 4 day),
deals.del_date = Date_add(Curdate(), INTERVAL 4 day)
WHERE 0 = (SELECT resort_id_count
FROM (SELECT Count(rst_id) AS resort_id_count
FROM vcd_resorts
WHERE rst_supersaver_resort = 1
AND rst_live_date BETWEEN Curdate() + 1 AND
Curdate() + 4)
temp)
AND resorts.rst_supersaver_resort = 1
AND resorts.rst_id = deals.del_resort_id
AND deals.del_supersaver_deal = 1
AND resorts.rst_id = (SELECT resort_id
FROM (SELECT rst_id AS resort_id
FROM vcd_resorts
WHERE rst_supersaver_resort = 1
ORDER BY rst_live_date ASC
LIMIT 1) temp1)
i have placed one more condition which replaced order by and limit
Hi I have below 5 mysql queries, i want to see output of all queries in by executing a single query.
please let me know how can i join all these queries.
1.
select sum(msu)
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07';
2.
select *
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07'
order by dt;
3.
select admin,sum(msu)
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07'
group by admin;
4.
SELECT admin, sum(msu)
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07'
group by admin
order by msu desc
limit 25;
Select ADMIN1,WEEK1,WEEK2,WEEK3,
(((WEEK3-WEEK2)/WEEK2)*100) as percentage_change,
(WEEK3-WEEK2) as MSU_Difference
from
((select admin as ADMIN1, sum(msu) as WEEK1
from wgr_raw
where dt >= date_sub(date('2013-11-01'),
INTERVAL 25 DAY) and dt < date_sub(date('2013-11-07'),
INTERVAL 18 DAY)
group by admin
order by WEEK1) as q1,
(select admin as ADMIN2, sum(msu) as WEEK2
from wgr_raw
where dt >= date_sub(date('2013-11-01'),
INTERVAL 18 DAY) and dt < date_sub(date('2013-11-07'),
INTERVAL 11 DAY)
group by admin
order by WEEK2) as q2,
(select admin as ADMIN3, sum(msu) as WEEK3
from wgr_raw where dt >= date_sub(date('2013-11-01'),
INTERVAL 11 DAY) and dt < date_sub(date('2013-11-07'),
INTERVAL 4 DAY)
group by admin
order by WEEK3) as q3)
where ADMIN1=ADMIN3 and ADMIN2=ADMIN3
group by admin1
order by WEEK1 desc
limit 25;
5.
select dt,sum(msu)
from wgr_raw
where dt >= date_sub(date('2013-11-01'),
INTERVAL 11 DAY)
group by dt
limit 7;
You can merge n number of select queries using UNION but there is one condition in UNION. Your all select fields should be same and order by will be common.
(
(SELECT a, b FROM tbl WHERE id >= 50 and id <= 100)
UNION
(SELECT a, b FROM tbl WHERE id >= 150 and id <= 200)
UNION
(SELECT a, b FROM tbl WHERE id >= 250 and id <= 300)
UNION
(SELECT a, b FROM tbl WHERE id >= 350 and id <= 400)
)
ORDER BY a
I need to select all users who "fits" in theirs working timetables.
Table in MySQL
Timetable:
user_id PRIMARY
day_number(0-sunday 6-saturday) PRIMARY (one user - one day)
start start worktime
end end worktime
Sample user:
user_id = 1
day_number = 1
start = 10:00
end = 18:00
user_id = 1
day_number = 2
start = 12:00
end = 18:00
user_id = 1
day_number = 3
start = 14:00
end = 16:00
Now I want select every user who works from 1(Monday) to 3(Wednesday) from 14:00 to 16:00.
Sample user (with id 1) should be included.
Any Ideas?
SELECT user_id
FROM my_table
NATURAL JOIN (SELECT 1 day_number UNION ALL SELECT 2 UNION ALL SELECT 3) days
JOIN (SELECT MAKETIME(14,0,0) start, MAKETIME(16,0,0) end) times
ON my_table.start <= times.start
AND my_table.end >= times.end
GROUP BY user_id
HAVING COUNT(DISTINCT my_table.day_number) = 3 -- number of days in range
See it on sqlfiddle.
Try this query
SELECT *
FROM `Timetable`
WHERE day_number between
1 and 3
AND TIME_TO_SEC( start ) <= TIME_TO_SEC( '14:00' )
AND TIME_TO_SEC( end ) >= TIME_TO_SEC( '16:00' )
Or
SELECT *
FROM `Timetable`
WHERE day_number in (1,2,3 )
AND TIME_TO_SEC( start ) <= TIME_TO_SEC( '14:00' )
AND TIME_TO_SEC( end ) >= TIME_TO_SEC( '16:00' )
Try the code below:
Select * from Timetable
Where day_number>=1 and day_number <=3 And
hour(start) >= 12 and hour(end)<= 16