I have the following table
UserID, Cost, date
1. 23. 2015-04-02
2. 17. 2015-03-14
1. 63. 2015-09-23
2. 49. 2013-03-17
2. 12. 2013-04-23
1. 96. 2016-01-01
What I want is a list of USERID & date with the largest cost
So
Userid 1 cost 96 date 2016-01-01
Userid 2 cost 49 date 2013-03-17
I have tried
select date, userid, max(cost) from table group by userid
But I'm confused with will the date always be from the correct row
Thanks
In SQLite 3.7.11 or later, values from other columns are guaranteed to come from a row that matches the max().
Consider a generalized approach for most RDMS versions. Below uses a derived table subquery:
SELECT t2.UserID, t2.MaxOfCost, t1.Date
FROM Table t1
INNER JOIN
(SELECT UserID, Max(Cost) As MaxOfCost,
FROM Table) t2
ON t1.UserID = t2.UserID
AND t1.Cost = t2.MaxOfCost
Related
I have a sqlite database with this info
id
pcs
dollars
year
10
25
150
2021
10
20
160
2021
10
22
120
2022
11
12
130
2021
11
10
100
2022
I want to get this
id
pcs2021
dollars2021
pcs2022
dollars2022
10
45
310
22
120
11
12
130
10
100
I got this:
SELECT id, SUM(pcs), SUM(dollars) FROM Table GROUP BY id
But I can't find the way to get the SUM of each year separately.
I tried something like:
SELECT id, (SELECT SUM(pcs) FROM Table WHERE id=id AND year=2021) AS pcs2021, (SELECT SUM(dollars) FROM Table WHERE id=id AND year=2021) AS dollars2021, (SELECT SUM(pcs) FROM Table WHERE id=id AND year=2022) AS pcs2022, (SELECT SUM(dollars) FROM Table WHERE id=id AND year=2022) AS dollars2022, FROM Table GROUP BY id
but it doesn't work.....
Thank you for your help.
Using :-
SELECT id, SUM(pcs) AS pcs2021, SUM(dollars) AS dollars2021 FROM `Table` WHERE year = 2021 GROUP BY id;
results in :-
note the above assumes year is an integer so you may have to enclose the literal in single quotes.
Additional (re comment)
My problem is when I want to put different columns with SUM of values for each year
An issue you are having is that id=id will always be true and thus you will sum all rows, irrespective of the id, for the year and get the result (when the syntax is correct):-
That is id is the id of the sub query when you want to compare against the id currently being processed by the main query.
To do this you can give the main query an alias using the AS clause and then refer to the id of the alias so (where the main query is given the alias of a):-
SELECT
id,
(SELECT sum(pcs) FROM `table` WHERE id=a.id AND year='2021') AS pcs2021,
(SELECT sum(dollars) FROM `table` WHERE id=a.id AND year='2021') AS dollars2021,
(SELECT sum(pcs) FROM `table` WHERE id=a.id AND year='2022') AS pcs2022,
(SELECT sum(dollars) FROM `table` WHERE id=a.id AND year='2022') AS dollars2022
FROM `table` AS a
GROUP BY id
;
The result being :-
Note the use of Table as a table name will result in a syntax error if it is not enclosed as Table is an SQLite keyword.
I have created a dataset "Orders" to test sqlite with structure
CREATE TABLE Orders (
OrderID INTEGER PRIMARY KEY AUTOINCREMENT
OrderDate TIMESTAMP DEFAULT (CURRENT_TIMESTAMP)
CustomerID VARCHAR(20)
OrderValue DECIMAL (8, 3) NOT NULL
);
I filled the table with sample data
ID Date Customer Value($)
6 11-09-2019 Eva 6946.3
7 11-10-2019 John 850.6
8 11-11-2019 Helen 9855.0
9 11-12-2019 Maria 765.2
11 11-13-2019 Gui 1879.5 --< I removed ID 10 purposely
12 11-14-2019 Eric 600.0
13 11-15-2019 Paul 12890.1
How could I identify in same row both records 11 and 9, given the parameter :date, to represent the last sale of orderdate = :date and the immediately forward, or in case I changed record 9 to same date of 11, I get 8 (the last sale of last day)?
pseudo-code
select last 2 order where orderdate <= :date inner join (? a relation to put both in same row)
Step one is to replace your 'MM-DD-YYYY' date strings with ones that can be sorted - 'YYYY-MM-DD', for example (Then you can use the date and time functions on them as well if needed). Since your orderdate column has a default value of CURRENT_TIMESTAMP, but you're just showing the date and that not in the same format that uses, I assume you're inserting your dates manually instead of letting them be automatically generated on insert? The column names of your sample data table don't match up with the ones in your table definition either... that's confusing.
Anyways, since you said you want the values in the same row, the lead() window function comes into play (Requires Sqlite 3.25 or newer). Something like:
WITH cte AS
(SELECT orderid, orderdate, customerid, ordervalue
, lead(orderid, 1) OVER bydate AS next_id
, lead(orderdate, 1) OVER bydate AS next_date
, lead(customerid, 1) OVER bydate AS next_customer
, lead(ordervalue, 1) OVER bydate AS next_value
FROM orders
WINDOW bydate AS (ORDER BY orderdate))
SELECT * FROM cte WHERE orderdate = :date;
gives for a :date of '2019-11-12':
orderid orderdate customerid ordervalue next_id next_date next_customer next_value
---------- ---------- ---------- ---------- ---------- ---------- ------------- ----------
9 2019-11-12 Maria 765.2 11 2019-11-13 Gui 1879.5
i have the following table where i have the date( not a primary key) and rating ('A' being the highest grade):
date rating
03-10-2010 C
03-09-2010 C
03-08-2010 B
03-07-2010 B
03-06-2010 B
03-05-2010 B
03-04-2010 A
I need to make a query where i compare the rating in order to return the result for each 'date'.
For example. considering the date 03-10-2010, i want to know when the last rating downgrade happened. if the downgrade was 1 day ago return '1' as result, if it was 2 days ago return '2' and if was older than 3 days return 0.
And i would do the same query for each date, getting an array with the results.
i'm stuck trying to do this and i have no more ideas how to do it. Anyone can help me please?
thanks.
You want the difference, in days, between the date of each record and the date of the record before the last downgrade.
When you have a specific record, the record before the last downgrade is the record that
has a higher rating than this record, and
has a lower date than this record, and
is the latest record of those.
In SQL, this can be done with a correlated subquery:
SELECT date,
rating,
(SELECT date
FROM MyTable AS downgrade
WHERE downgrade.date < MyTable.date
AND downgrade.rating < MyTable.rating
ORDER BY date DESC
LIMIT 1) AS downgrade_date
FROM MyTable
date rating downgrade_date
---------- ---------- ----------
2010-03-04 A
2010-03-05 B 2010-03-04
2010-03-06 B 2010-03-04
2010-03-07 B 2010-03-04
2010-03-08 B 2010-03-04
2010-03-09 C 2010-03-08
2010-03-10 C 2010-03-08
To compute the difference, convert the date into a numeric value.
You can then use this value for further computations:
SELECT date,
rating,
CASE
WHEN days <= 3 THEN days
ELSE 0
END AS whatever
FROM (SELECT date,
rating,
julianday(date) -
julianday((SELECT date
FROM MyTable AS downgrade
WHERE downgrade.date < MyTable.date
AND downgrade.rating < MyTable.rating
ORDER BY date DESC
LIMIT 1)) AS days
FROM MyTable)
I've just started learning SQLite, and had a question.
Here is an example of what I mean.
This is my CSV:
date
2010-10-24
2010-10-31
2010-11-01
2011-02-14
2011-02-15
2011-02-16
2011-10-01
2012-01-15
2012-05-12
2012-05-14
2012-08-12
2012-08-26
My code:
SELECT STRFTIME('%Y-%m', date) AS 'month', COUNT() AS 'month_count'
FROM tableName
GROUP BY STRFTIME('%Y-%m', date);
The result (in comma-delimited form):
month, month_count
2010-10, 2
2010-11, 1
2011-02, 3
2011-10, 1
2012-01, 1
2012-05, 2
2012-08, 2
What I'm looking for now, is a way to get the average number of 'month_count' per month, which is of course different from just the average of 'month_count'. That is, the former equals 0.55, while the latter equals 1.71, and I'm trying ti calculate the former.
I tried using AVG(COUNT()), though that obviously made no logical sense.
I'm guessing I'd have to store the code-generated table as a temporary file, then get the average from it, though I'm not sure how to properly write it.
Does anyone know what I'm missing?
Try the code below:
create table test(date date);
insert into test values ('2010-10-24');
insert into test values ('2010-10-31');
insert into test values ('2010-11-01');
insert into test values ('2011-02-14');
insert into test values ('2011-02-15');
insert into test values ('2011-02-16');
insert into test values ('2011-10-01');
insert into test values ('2012-01-15');
insert into test values ('2012-05-12');
insert into test values ('2012-05-14');
insert into test values ('2012-08-12');
insert into test values ('2012-08-26');
SELECT a.tot_months
, b.month_diff
, cast(a.tot_months as float) / b.month_diff avg_count
FROM (SELECT COUNT(*) tot_months FROM test) a
, (SELECT cast((strftime('%m',max(date))+12*strftime('%Y',max(date))) as int) -
cast((strftime('%m',min(date))+12*strftime('%Y',min(date))) as int) as 'month_diff'
FROM test) b
;
Output:
C:\scripts>sqlite3 < foo.sql
12|22|0.545454545454545
I am using SQLite 3.7.4 and have a table that includes:
TABLE: 'Orders'
ID OrderDate
1234 2011-06-01 00:00:00
1245 2011-06-04 00:00:00
1234 2011-06-05 00:00:00
I'd like to be able to select the 'OrderDate' & 'ID' where, for a given OrderDate there is a previous order in the last 1 week.
So, for the data above:
The first record ID 1234 has an order
on 2011-06-01 00:00:00, but has none
previous - so isn't selected.
The next record ID 1245 has an order
on 2011-06-04 00:00:00 but none in
week prior to 2011-06-04, so not
selected.
The 3rd record ID 1234 order made on
2011-06-05 00:00:00 has a previous
order on 2011-06-01, so this record
is selected.
I have just about managed to get my head around using strftime('%s',OrderDate) for date differences,but can't work out how to query by taking the yyyy-mm-dd part of the OrderDate record and looking back '-7 days' to see if there are 1 or more records within that range ?
Any guideance appreciated :)
Not certain I understand, but this gives the output you're looking for, given the sample data.
sqlite> select o1.id, o1.orderdate from orders o1
...> inner join orders o2 on (o1.id = o2.id
...> and o2.orderdate >= date(o1.orderdate, '-7 day')
...> and o2.orderdate < o1.orderdate);
1234|2011-06-05
You should probably look at SQLite Date and Time Functions.