Hey guys, I've tried to get this right but I can't, maybe you can point me in the right direction
I have 3 columns, 'url_id', 'timestamp' and 'o'. I need to group by 'url_id' and sort by the most current timestamp.
table "example"
timestamp | url_id | o
----------------------------
2000 | 1 | 50
2007 | 1 | 70
2011 | 1 | 90
2001 | 2 | 20
2006 | 2 | 50
2009 | 2 | 40
2011 | 2 | 10
'o' is the value at the end I want. I was trying to do this with a subquery but kept getting the oldest value (tried order by, and had no luck).
What am I doing wrong? Is what I'm looking for actually require a subquery?
SELECT url_id
, MAX(timestamp) AS currentTS
FROM yourTable
GROUP BY url_id
ORDER BY currentTS DESC
Aftre you last explanation, I think you need to JOIN the above query to your original table, like this:
SELECT y.timestamp
, y.url_id
, y.o
FROM yourTable y
JOIN
( SELECT url_id
, MAX(timestamp) AS currentTS
FROM yourTable
GROUP BY url_id
) AS grp
ON grp.url_id = y.url_id
AND grp.currentTS = y.timestamp
ORDER BY y.timestamp DESC
Note: if there are two (or more) rows with same url_id and same timestamp, they'll both (or all) appear at the results.
Related
I have a 'sales' table called phpbb_sold which records each 'sale' as a row.
I am able to use a WHERE clause with the uitemid field to select one particular item in the sales records, as seen below:
SELECT uitemid, locktime, migrated_sold FROM phpbb_sold WHERE uitemid=342;
+---------+------------+---------------+
| uitemid | locktime | migrated_sold |
+---------+------------+---------------+
| 342 | 1632523854 | 1 |
| 342 | 1634239244 | 1 |
| 342 | 1634240072 | 1 |
| 342 | 1636367271 | 1 |
+---------+------------+---------------+
uitemid = number that identifies this as a sale of X item. locktime = UNIX timestamp that shows the datetime that the item was sold. migrated_sold = the quantity of the item sold. So this is nice, I have a table that keeps a record of each sale as it happens.
What I want to achieve though, is a record of the total number of sales of this item type, for each day in a 6 month period spanning back from the current date, and including each day regardless of whether a sale was made or not. So the desired output of my query would be:
SELECT (the query I want goes here) and returns the following rows...;
+------------+------------+
| caldate | sold_total |
+------------+------------+
| 2021-09-23 | 2 |
| 2021-09-24 | 0 |
| 2021-09-25 | 1 |
| 2021-09-26 | 0 |
| 2021-09-27 | 0 |
| 2021-09-28 | 1 |
+------------+------------+
Note that each day is included as a row in the results, even where the sales total for that day is 0. I read that to do this, I would be required to create a calendar table with one column and all the days I want as rows, so I went ahead and did that:
SELECT caldate FROM phpbb_calendar;
+------------+
| caldate |
+------------+
| 2021-09-23 |
| 2021-09-24 |
| 2021-09-25 |
| 2021-09-26 |
| 2021-09-27 |
| 2021-09-28 |
+------------+
Now all that remains is for me to make the query. I need to somehow return all the rows from the phpbb_calendar table, joining the data from sum() (?) of the total migrated_sold for those days where exists, and a 0 where no sales took place.
I anticipated some issues with the UNIX timestamp, but it's okay because I am able to get caldate and locktime fields to be the same format by using from_unixtime(locktime, '%Y-%m-%d'), so both dates will be in the YYYY-MM-DD format for comparison.
Please could someone help me with this. I've gotten so close every time but it seems that everyone else's request is only slightly different from mine, so existing questions and answers have not been able to satisfy my requirements.
End goal is to use a JS chart library (AnyChart) to show a line graph of the number of sales of the item over time. But to get there, I first need to provide it with the query necessary for it to display that data.
Thanks
Update
Using this query:
SELECT c.caldate, u.uitemid, sum(v.migrated_sold) as total_sales
from phpbb_calendar c cross join
(select distinct uitemid from phpbb_sold) u left join
phpbb_sold v
on c.caldate = from_unixtime(v.locktime, '%Y-%m-%d') WHERE u.uitemid = 39 and c.caldate <= curdate() GROUP BY c.caldate ORDER BY c.caldate;
Returns:
But as you can see, it's just tallying up the total number of sales ever made or something - its clearly incrementing in a way I don't understand.
I don't want it to do that - I want it to count the number of total sales on each day individually. The results should look like this:
So that what is returned is basically a 'histogram' of sales, if any occurred, including 'empty' days where there were no sales (so these empty days must still be returned as rows).
SELECT c.caldate, u.uitemid, COALESCE(SUM(v.migrated_sold), 0) AS total_sales
FROM phpbb_calendar c
CROSS JOIN (SELECT DISTINCT uitemid FROM phpbb_sold WHERE uitemid = 37) u
LEFT JOIN phpbb_sold v
ON v.locktime BETWEEN UNIX_TIMESTAMP(TIMESTAMP(c.caldate)) AND UNIX_TIMESTAMP(TIMESTAMP(c.caldate, '23:59:59'))
AND u.uitemid = v.uitemid
WHERE c.caldate BETWEEN CURDATE() - INTERVAL 6 MONTH AND CURDATE()
GROUP BY c.caldate, u.uitemid
ORDER BY c.caldate;
N.B. I have changed your join to use the unix_timestamp as it should be more efficient and it can use any existing index on locktime
check this out:
select id, d, sum(s) from (
select U.id, d, 0 s from (
select adddate(current_date(),-rows.r) d from (
select (#row_number := #row_number + 1) r
from information_schema.columns,
(SELECT #row_number := 0) AS x
limit 200
) rows
) dates,
(SELECT distinct uitemid id FROM `phpbb_sold`) U
where d > adddate(current_date(), interval -6 month)
union
select uitemid, date(from_unixtime(locktime)),sum(migrated_sold)
from `phpbb_sold`
group by uitemid, date(from_unixtime(locktime))
) sales_union
group by id, d
order by id, d;
see dbfiddle
no need for calendar table
Here's what I'm trying to do. Let's say I have this table t:
key_id | id | record_date | other_cols
1 | 18 | 2011-04-03 | x
2 | 18 | 2012-05-19 | y
3 | 18 | 2012-08-09 | z
4 | 19 | 2009-06-01 | a
5 | 19 | 2011-04-03 | b
6 | 19 | 2011-10-25 | c
7 | 19 | 2012-08-09 | d
For each id, I want to select the row containing the minimum record_date. So I'd get:
key_id | id | record_date | other_cols
1 | 18 | 2011-04-03 | x
4 | 19 | 2009-06-01 | a
The only solutions I've seen to this problem assume that all record_date entries are distinct, but that is not this case in my data. Using a subquery and an inner join with two conditions would give me duplicate rows for some ids, which I don't want:
key_id | id | record_date | other_cols
1 | 18 | 2011-04-03 | x
5 | 19 | 2011-04-03 | b
4 | 19 | 2009-06-01 | a
How about something like:
SELECT mt.*
FROM MyTable mt INNER JOIN
(
SELECT id, MIN(record_date) AS MinDate
FROM MyTable
GROUP BY id
) t ON mt.id = t.id AND mt.record_date = t.MinDate
This gets the minimum date per ID, and then gets the values based on those values. The only time you would have duplicates is if there are duplicate minimum record_dates for the same ID.
I could get to your expected result just by doing this in mysql:
SELECT id, min(record_date), other_cols
FROM mytable
GROUP BY id
Does this work for you?
To get the cheapest product in each category, you use the MIN() function in a correlated subquery as follows:
SELECT categoryid,
productid,
productName,
unitprice
FROM products a WHERE unitprice = (
SELECT MIN(unitprice)
FROM products b
WHERE b.categoryid = a.categoryid)
The outer query scans all rows in the products table and returns the products that have unit prices match with the lowest price in each category returned by the correlated subquery.
I would like to add to some of the other answers here, if you don't need the first item but say the second number for example you can use rownumber in a subquery and base your result set off of that.
SELECT * FROM
(
SELECT
ROW_NUM() OVER (PARTITION BY Id ORDER BY record_date, other_cols) as rownum,
*
FROM products P
) INNER
WHERE rownum = 2
This also allows you to order off multiple columns in the subquery which may help if two record_dates have identical values. You can also partition off of multiple columns if needed by delimiting them with a comma
This does it simply:
select t2.id,t2.record_date,t2.other_cols
from (select ROW_NUMBER() over(partition by id order by record_date)as rownum,id,record_date,other_cols from MyTable)t2
where t2.rownum = 1
If record_date has no duplicates within a group:
think of it as of filtering. Simpliy get (WHERE) one (MIN(record_date)) row from the current group:
SELECT * FROM t t1 WHERE record_date = (
select MIN(record_date)
from t t2 where t2.group_id = t1.group_id)
If there could be 2+ min record_date within a group:
filter out non-min rows (see above)
then (AND) pick only one from the 2+ min record_date rows, within the given group_id. E.g. pick the one with the min unique key:
AND key_id = (select MIN(key_id)
from t t3 where t3.record_date = t1.record_date
and t3.group_id = t1.group_id)
so
key_id | group_id | record_date | other_cols
1 | 18 | 2011-04-03 | x
4 | 19 | 2009-06-01 | a
8 | 19 | 2009-06-01 | e
will select key_ids: #1 and #4
SELECT p.* FROM tbl p
INNER JOIN(
SELECT t.id, MIN(record_date) AS MinDate
FROM tbl t
GROUP BY t.id
) t ON p.id = t.id AND p.record_date = t.MinDate
GROUP BY p.id
This code eliminates duplicate record_date in case there are same ids with same record_date.
If you want duplicates, remove the last line GROUP BY p.id.
This a old question, but this can useful for someone
In my case i can't using a sub query because i have a big query and i need using min() on my result, if i use sub query the db need reexecute my big query. i'm using Mysql
select t.*
from (select m.*, #g := 0
from MyTable m --here i have a big query
order by id, record_date) t
where (1 = case when #g = 0 or #g <> id then 1 else 0 end )
and (#g := id) IS NOT NULL
Basically I ordered the result and then put a variable in order to get only the first record in each group.
The below query takes the first date for each work order (in a table of showing all status changes):
SELECT
WORKORDERNUM,
MIN(DATE)
FROM
WORKORDERS
WHERE
DATE >= to_date('2015-01-01','YYYY-MM-DD')
GROUP BY
WORKORDERNUM
select
department,
min_salary,
(select s1.last_name from staff s1 where s1.salary=s3.min_salary ) lastname
from
(select department, min (salary) min_salary from staff s2 group by s2.department) s3
I have a MySQL table for product orderings named TABLE1.
Date means the date purchase has been made
The table has other columns that currently have no influence.
PRODUCT_ID | DATE | other columns
3 |2018-02-01 | other values
3 |2018-02-03 | other values
3 |2018-02-07 | other values
3 |2018-02-07 | other values
3 |2018-03-02 | other values
I know that the first time the product 3 has been ordered, is 2018-02-01
SELECT DATE FROM TABLE1 WHERE PRODUCT_ID = '3' ORDER BY DATE ASC LIMIT 1
How do I select count of product orderings per day within range of 2018-02-01 and 2019-03-16 (today) so that I could get a table like that:
DATE | ORDERS_PER_DAY
2018-02-01 | 1
2018-02-02 | 0
2018-02-03 | 1
...
2018-02-07 | 2
...
2018-03-02 | 1
...
2018-03-15 | 0
2018-03-16 | 0
Thanks for help!
You can simply use GROUP BY clause to do it.
SELECT `DATE`, COUNT(`PRODUCT_ID`) AS ORDERS_PER_DAY
FROM TABLE1
WHERE `DATE` BETWEEN '2018-02-01' AND CURDATE()
GROUP BY `DATE`
This query will result in filtering the records on your required date range and then grouping it by each day where there is data.
My syntax may not be exactly correct, but could you try something like this using the GROUP BY clause.
SELECT DATE, COUNT(*) AS ORDERS_PER_DAY
FROM TABLE1
GROUP BY DATE, PRODUCT_ID
HAVING PRODUCT_ID = '3'
you can read more about this here: https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
I have some data row in my table.
I want to select the Age which occurs the most.
Person | Group | Age
---
Bob | 1 | 32
Jill | 1 | 32
Shawn| 1 | 42
Jake | 2 | 29
Paul | 2 | 36
Laura| 2 | 39
Desired set:
The age that appears the most is 32.
Use the following query
select Person, count(*) as c FROM tableName GROUP BY Age
You can add the limit 1 to get the only only record and order by to get the maximum or minimum age. Use following query
select Person, count(*) as c,Age FROM profile GROUP BY Age ORDER BY c desc LIMIT 0,1
Try something like this
SELECT Person,Group,Age,MAX(field_name)
FROM table_name;
After grouping the values you can select the top 1 as below : This would select 32 as answer
SELECT TOP (1) Age
FROM tablename
GROUP BY age
ORDER BY COUNT(*) DESC
SELECT age FROM my_table GROUP BY age ORDER BY COUNT(*) DESC LIMIT 1;
Fairly obviously, in the case of a tie, this result will be misleading.
My Db design is :
Tbl_id booked_by date
1 W 2014-02-01
2 P 2014-02-01
3 P 2014-02-01
4 P 2014-02-01
5 W 2014-02-04
6 W 2014-02-04
7 P 2014-02-04
I want to display counting of W , P Where given Date and Grouped by Date and with Using php mysql ..
like
I NEED OUTPUT LIKE THIS:
Tbl_id W P date
1 1 3 2014-02-01
2 2 1 2014-02-04
I need Mysql Query to get output given in above..
You need to use SUM aggregate function for summation and a temp row number for Tbl_id.
select
#rwnm:=#rwnm+1 as Tbl_id,
sum(No_people) as No_people,
sum(Breakfast) as Breakfast,
sum(Lunch) as Lunch,
date
from my_table, ( select #rwnm := 0 ) rownums
group by date
You need the SUM() function, not the COUNT().
SELECT
SUM(No_people),
SUM(Breakfast),
SUM(Lunch),
`date`
FROM yourTable
GROUP BY `date`
I did not include the Tbl_id, because every column you select must be used with an aggregate function or be included in the group by clause. Otherwise it's undetermined which row of the group is selected. Selecting it anyway only works in MySQL, but it does not adhere to the SQL standard. If you want some kind of row number instead either Ravinder's approach or create one on application level (which certainly is easier).
UPDATE:
SELECT
SUM(booked_by = 'W') AS W,
SUM(booked_by = 'P') AS P,
`date`
FROM yourTable
GROUP BY `date`
You still need the SUM() function. booked_by = 'whatever' evaluates to true (1) or false (0).
If you want just the result without slno below query will work fine
SELECT
SUM(No_People) as No_People,
SUM(Breakfast) as Breakfast,
Sum(Lunch) as Lunch,
`date` as date
FROM table_Name
GROUP BY `date`
Output:
No_people Breakfast Lunch date
84 112 160 2014-02-11
116 96 118 2014-02-04
But if you also want serial no. to be displayed then below query will work
SELECT
#slno := #slno + 1 as slno
SUM(No_People) as No_People,
SUM(Breakfast) as Breakfast,
Sum(Lunch) as Lunch,
`date` as date
FROM table_Name, (select #slno := 0 ) sln
GROUP BY `date`
Output:
slno No_people Breakfast Lunch date
1 84 112 160 2014-02-11
2 116 96 118 2014-02-04
Consider the following data set...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,booked_by CHAR(1) NOT NULL
,date DATE NOT NULL
);
INSERT INTO my_table VALUES
(1,'W','2014-02-01'),
(2,'P','2014-02-01'),
(3,'P','2014-02-01'),
(4,'P','2014-02-01'),
(5,'W','2014-02-04'),
(6,'W','2014-02-04'),
(7,'P','2014-02-04');
Here's a pivot query...
SELECT date
, COUNT(CASE WHEN booked_by = 'W' THEN 'foo' END) W
, COUNT(CASE WHEN booked_by = 'P' THEN 'foo' END) P
FROM my_table
GROUP
BY date;
+------------+---+---+
| date | W | P |
+------------+---+---+
| 2014-02-01 | 1 | 3 |
| 2014-02-04 | 2 | 1 |
+------------+---+---+
In my opinion, a better idea (more flexible, more scalable) is simply to return a GROUPED (and, therefore, ordered) result set and handle the rest at in the presentation layer (e.g. a simple PHP loop)...
SELECT date,booked_by,COUNT(*) ttl FROM my_table GROUP BY date,booked_by;
+------------+-----------+-----+
| date | booked_by | ttl |
+------------+-----------+-----+
| 2014-02-01 | P | 3 |
| 2014-02-01 | W | 1 |
| 2014-02-04 | P | 1 |
| 2014-02-04 | W | 2 |
+------------+-----------+-----+