GROUP BY in Django ORM with aggregation - sql

I need to implement such query:
Table1
|Id | Name |
| 1 | Peter |
| 2 | Andrew |
Table2
| Score | Table1Id |
| 10 | 1 |
| 20 | 1 |
| 100 | 1 |
| 0 | 2 |
| 30 | 2 |
I need select for all names {name, min_score, max_score}
{Peter, 10, 100}
{Andrew, 0, 30}
Something like:
SELECT DISTINCT MIN(score), MAX(score) Table1.name FROM Table1, Table2 WHERE Table1.Id = Table2.Table1Id GROUP BY Table1.Name
In ORM it something like:
Table2.objects.all().annotate(min_score=Min('score'), max_score=Max('score')).values('Table1.Name!!!!', 'min_score', 'max_score')

try this:
Table2.objects.values('table1__name').annotate(min_score=Min('score'), max_score=Max('score'))
the annotated fields will be added to the result, they don't need to go in values(...), but whatever you put in values(...) will be used as the GROUP BY field(s)

Related

How can I subtract two row's values within same column using sql query in access?

(query access)
This is the table structure:
+-----+--------+--------+
| id | name | sub1 |
+-----+--------+--------+
| 1 | ABC | 6.27% |
| 2 | ABC | 7.47% |
| 3 | PQR | 3.39% |
| 4 | PQR | 2.21% |
+-----+--------+--------+
I want to subtract Sub1
Output should be:
+-----+--------+---------+------------------------------------+
| id | name | sub1 | |
+-----+--------+---------+------------------------------------+
| 1 | ABC | 6.27% | 0 First Rec no need Subtract |
| 2 | ABC | 7.47% | 1.2% <=(7.47-6.27) |
| 3 | PQR | 3.39% | 0 First Rec no need Subtract |
| 4 | PQR | 2.21% | -1.18% <=(2.21-3.39) |
+-----+--------+---------+------------------------------------+
Thank you so much.
If you can guarantee consecutive id values, then the following presents an alternative:
select t.*, nz(t.sub1-u.sub1,0) as sub2
from YourTable t left join YourTable u on t.name = u.name and t.id = u.id+1
Change YourTable to the name of your table.
This is painful, but you can do:
select t.*,
(select top 1 t2.sub1
from t as t2
where t2.name = t.name and t2.id < t.id
order by t2.id desc
) as prev_sub1
from t;
This gives the previous value or NULL for the first row. You can just use - for the subtraction.
An index on (name, id) would help a bit with performance. However, if you can upgrade to a better database, you can then just use lag().

Multi not like expression sql

So basically i've a table like this.
+--------+----------+
| name | Group |
+--------+----------+
| xxxx | 1 |
| yyyy | 1 |
| xxxx | 2 |
| yyyy | 3 |
| xxxx | 4 |
+--------+----------+
and i don't want to display any records that have name xxxx in their group.
You seem want :
select t.*
from table t
where not exists (select 1 from table t1 where t1.group = t.group and t1.name = 'xxxx')
You need a subquery at first to identify groups you do not need. then you need to filter it from main query
SELECT * FROM Table1
Where group not in ( select group from Table1 where name != 'xxxx')

Using SWITCH() to split data from a column into distinct columns, with associated data in reach row

I'm not quite sure how to properly phrase the question, but I am basically trying to develop an SQL query that SELECTs information from this table:
-------------------
| id | Val | Date |
|----|-----|------|
| 1 | A | 10/9 |
| 1 | B | 3/14 |
| 2 | A | 1/6 |
| 3 | A | 4/4 |
| 4 | B | 7/12 |
| 5 | A | 8/6 |
-------------------
And produces a table that looks like this:
------------------------------------------------
| id | Val_1 | Val_1_Date | Val_2 | Val_2_Date |
|----|-------|------------|-------|-------------
| 1 | A | 10/9 | B | 3/14 |
| 2 | A | 1/6 | | |
| 3 | A | 4/4 | | |
| 4 | | | B | 7/12 |
| 5 | A | 8/6 | | |
------------------------------------------------
I have already begun and developed the query to pull out the values in the Val fields into distinct columns:
SELECT * FROM
(
SELECT id, MAX(SWITCH( val='A', 'A')) as Val_1,
MAX(SWITCH( val='B', 'B')) as Val_2
FROM table1 GROUP BY id
)a
WHERE Val_1 IS NULL OR Val_2 IS NULL;
How would I expand on this to pull out their associated dates?
(I am using SWITCH() instead of CASE WHEN because I am using a driver similar to that of MS Access.)
Thanks!
I think following should work:
select id, SWITCH( val='A', 'A') as Val_1, SWITCH( val='A', Date) as Val_1_Date, SWITCH( val='B', 'B') as Val_2, SWITCH( val='B', Date) as Val_2_Date FROM table1 GROUP BY id
I do not prefer switches, so here is a query that does what you want without switches. This also answers your previous question.
Select distinct table1.ID, tableA.Val as Val_1, tableA.Date as Val_1_Date,
tableB.Val as Val_2, tableB.Date as Val_2_Date
FROM table1 left outer join
table1 as tableA on table1.id = tableA.id and tableA.Val = 'A' left outer join
table1 as tableB on table1.id = tableB.id and tableB.Val = 'B'
You can use ISNULL if that is preferred. This works because the first tables selects a distinct column of ID's, and the two joins get the A and B values. When creating selects using this method, make sure that you use tableA.Val = 'A' in the join conditions, and not in the where clause. Having tableA.Val = 'A' in the where clause will filter out all NULL's.

Multi-Table Selecting with Count of Foreign Key Referred Rows

I've tables related with foreign keys and i try to prepare a view to compose them via inner joins on SQL Server. I don't know if using inner join's is the way, but I can't get what I want anyway.
Tables are like below (I have more than 2 tables):
Table1:
| ID | Bla Bla... |
Table2:
| ID | Table1ID | Bla Bla... |
The query I tried is like this:
Select
Table1.ID, COUNT(Table2.ID) as FooCount
From
Table1
Inner Join
Table2 on Table2.Table1ID = Table1.ID
The result I want to see should be this:
| ID | FooCount |
-----------------------
| 1 | 45 |
| 2 | 75 |
| 3 | 98 |
| 4 | 100 |
| 5 | 11 |
| 6 | 37 |
How can I do this?
You don't even need a join to do this:
SELECT Table1Id AS ID, COUNT(*) as FooCount FROM Table2 GROUP BY Table1Id

How to apply a SUM operation without grouping the results in SQL?

I have a table like this one:
+----+---------+----------+
| id | group | value |
+----+---------+----------+
| 1 | GROUP A | 0.641028 |
| 2 | GROUP B | 0.946927 |
| 3 | GROUP A | 0.811552 |
| 4 | GROUP C | 0.216978 |
| 5 | GROUP A | 0.650232 |
+----+---------+----------+
If I perform the following query:
SELECT `id`, SUM(`value`) AS `sum` FROM `test` GROUP BY `group`;
I, obviously, get:
+----+-------------------+
| id | sum |
+----+-------------------+
| 1 | 2.10281205177307 |
| 2 | 0.946927309036255 |
| 4 | 0.216977506875992 |
+----+-------------------+
But I need a table like this one:
+----+-------------------+
| id | sum |
+----+-------------------+
| 1 | 2.10281205177307 |
| 2 | 0.946927309036255 |
| 3 | 2.10281205177307 |
| 4 | 0.216977506875992 |
| 5 | 2.10281205177307 |
+----+-------------------+
Where summed rows are explicitly repeated.
Is there a way to obtain this result without using multiple (nested) queries?
IT would depend on your SQL server, in Postgres/Oracle I'd use Window Functions. In MySQL... not possible afaik.
Perhaps you can fake it like this:
SELECT a.id, SUM(b.value) AS `sum`
FROM test AS a
JOIN test AS b ON a.`group` = b.`group`
GROUP BY a.id, b.`group`;
No there isn't AFAIK. You will have to use a join like
SELECT t.`id`, tsum.sum AS `sum`
FROM `test` as t GROUP BY `group`
JOIN (SELECT `id`, SUM(`value`) AS `sum` FROM `test` GROUP BY `group`) AS tsum
ON tsum.id = t.id