I have data (SELECT * FROM t) that looks like that
ID | VERSION | ...
====================
1 | 2 | ...
1 | 1 | ...
2 | 3 | ...
2 | 2 | ...
2 | 1 | ...
....
How can I take only the first row (with maximum version) for every unique ID value ?
ID | VERSION | ...
====================
1 | 2 | ...
2 | 3 | ...
....
You can use row_number analytic function to rank rows per ID column, then filter out only rows with rnb = 1 :
select *
from (
select t.*, row_number()over(partition by ID order by VERSION desc) rnb
from Your_table t
)
where rnb = 1
;
try
select t.ID, MAX(t.version) as version from t
group by t.ID
note: version is a reserved word, so i advise to chose some other column name.
for all results :
select *
from t
where (t.ID, t.version) in
(select t.ID, MAX(t.version) as version from t group by t.ID)
With SQLite, Given the tables below
_id Name
1 StudentA
2 StudentB
3 StudentC
and
id StudentId Test Score
1 1 A 5
2 1 B 5
3 1 A 6
4 1 B 6
5 2 A 3
6 2 B 3
7 2 A 4
or in SQL Form
BEGIN TRANSACTION;
DROP TABLE IF EXISTS "Results";
CREATE TABLE IF NOT EXISTS "Results" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"StudentId" INTEGER,
"Test" TEXT,
"Score" INTEGER,
FOREIGN KEY("StudentId") REFERENCES "Students"("_id")
);
DROP TABLE IF EXISTS "Students";
CREATE TABLE IF NOT EXISTS "Students" (
"_id" INTEGER PRIMARY KEY AUTOINCREMENT,
"Name" TEXT NOT NULL
);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (1,1,'A',5);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (2,1,'B',5);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (3,1,'A',6);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (4,1,'B',6);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (5,2,'A',3);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (6,2,'B',3);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (7,2,'A',4);
INSERT INTO "Students" ("_id","Name") VALUES (1,'StudentA');
INSERT INTO "Students" ("_id","Name") VALUES (2,'StudentB');
INSERT INTO "Students" ("_id","Name") VALUES (3,'StudentC');
COMMIT;
I would like to show which students have missed which tests and by how many times
The SQL query below gets me close but not exactly what I need
SELECT s.Name, r.Test, COUNT(r.Test) AS Count
FROM Students s
LEFT OUTER JOIN Results r ON s._id = r.StudentId
GROUP BY s._id, r.Test
Gives me the results table:-
Name Test Count
StudentA A 2
StudentA B 2
StudentB A 2
StudentB B 1
StudentC NULL 0
BUT I would like the table as shown below:-
Name Test Count
StudentA A 2
StudentA B 2
StudentB A 2
StudentB B 1
StudentC A 0
StudentC B 0
Is there any way to do this with SQLite?
Cross join the table Students with the distinct Tests and then left join to the table Results:
WITH cte AS (
SELECT *
FROM Students
CROSS JOIN (SELECT DISTINCT Test FROM Results)
)
SELECT c.Name, c.Test, COUNT(r.Test) AS Count
FROM cte c
LEFT OUTER JOIN Results r ON c._id = r.StudentId AND c.Test = r.Test
GROUP BY c.Name, c.Test
See the demo.
Or without the CTE:
SELECT s.Name, t.Test, COUNT(r.Test) AS Count
FROM Students s
CROSS JOIN (SELECT DISTINCT Test FROM Results) t
LEFT OUTER JOIN Results r ON s._id = r.StudentId AND t.Test = r.Test
GROUP BY s.Name, t.Test
See the demo.
Results:
| Name | Test | Count |
| -------- | ---- | ----- |
| StudentA | A | 2 |
| StudentA | B | 2 |
| StudentB | A | 2 |
| StudentB | B | 1 |
| StudentC | A | 0 |
| StudentC | B | 0 |
I have a table like this:
id | value
1 | a
1 | a
1 | b
1 | c
2 | a
2 | a
2 | a
2 | c
And I want to count(*) by id and then count(value==a) by id, which means this is the desired results:
id | total_counts | a_counts
1 | 4 | 2
2 | 4 | 3
I know how to do it by joining two subqueries, but is there an easier/faster way to do it? Like this pseudo-code:
SELECT id, COUNT(*) AS total_counts, COUNT(value==a) AS a_counts
FROM table
GROUP BY id
Not sure if there is a way to do the COUNT(value==a) part. Please kindly help.
You could use SUM:
SELECT id, COUNT(*) AS total_counts, SUM(value='a') AS a_counts
FROM table
GROUP BY id;
Or if you have SQLite 3.25 you could use windowed version:
SELECT /*DISTINCT*/
id,
COUNT(*) OVER(PARTITION BY id) AS total_counts,
COUNT(*) FILTER (WHERE value = 'a') OVER(PARTITION BY id) AS a_counts
FROM tab
I am maintaining table structure like below.
sortid | id | name
1 | 1 | aa
3 | 2 | cc
4 | 3 | cc
2 | 4 | bb
5 | 5 | dd
Where sortid is maintained according to ascending order of name.
Now I want to update name 'dd' to 'aa', such way that sort id is also updated to its correct value.
Update table set name="bb" where name like "dd";
After updating my table should become like below.
sortid | id | name
1 | 1 | aa
4 | 2 | cc
5 | 3 | cc
3 | 4 | bb
2 | 5 | aa
That sortid is the number of rows that would be sorted before this row.
So you can compute it by counting rows:
UPDATE MyTable
SET sortid = (SELECT COUNT(*)
FROM MyTable AS T2
WHERE T2.name < MyTable.name) +
(SELECT COUNT(*)
FROM MyTable AS T2
WHERE T2.name = MyTable.name
AND T2.id <= MyTable.id);
(The second subquery resolves duplicate sortid values that would result from duplicate names.)
I have two tables Department and Employee.
Department table looks like this:
ID DeptName
1 IT
2 CSE
3 ECE
Employee table :
ID DeptID EmployeeName Salary
1 1 John 10000
2 1 Bob 15000
3 2 Akon 12000
4 2 Smith 20000
Now I want to group the data in such a way that I get the following results which include these columns :
ID DeptName Employee
1 IT John,10000
Bob,15000
2 CSE Akon,12000
Smith,20000
Can we do something like this using SQL group functions or any other way?
Please help me.
Thanks,
Rajbir
This:
select final.deptId, d.deptName,
e3.employeename + ',' + cast(e3.salary as varchar) employee
from employee e3
left join (
select e1.id, e1.deptId from employee e1
left join employee e2
on e1.deptId = e2.deptId and e1.id > e2.id
where e2.id is null
) final on e3.id = final.id
left join department d on d.id = final.deptId
Results in:
+--------+----------+-------------+
| DEPTID | DEPTNAME | EMPLOYEE |
+--------+----------+-------------+
| 1 | IT | John,10000 |
| | | Bob,15000 |
| 2 | CSE | Akon,12000 |
| | | Smith,20000 |
+--------+----------+-------------+
Note that the "blank" values are actually filled with null values.
Let me know if you have any issue with it.