distinct sum does not distinct values - sqlite

I have 2 tables, reservations and articles:
Reservations
------------------------------
Id | Name | City |
------------------------------
1 | Mike | Stockholm
2 | Daniel | Gothenburg
2 | Daniel | Gothenburg
3 | Andre | Gothenburg (Majorna)
Articles
-------------------------------------------------------------
ArticleId | Name | Amount | ReservationId |
-------------------------------------------------------------
10 | Coconuts | 1 | 1
10 | Coconuts | 4 | 2
11 | Apples | 2 | 2
12 | Oranges | 2 | 3
I want to select Articles Name and the sum of Articles.Amount per Articles.ArticleId and Reservations.City.
My code:
SELECT distinct r.ID,a.Name as ArticleName,
sum(a.Amount) as ArticlesAmount,
substr(r.City,1,3) as ToCityName
FROM Reservations r
INNER JOIN Articles a
on r.Id = a.ReservationId
WHERE a.Name <> ''
GROUP BY ToCityName,a.ArticleId,a.Name
ORDER BY ToCityName ASC
This gives me following result:
Id | ArticleName | ArticlesAmount | ToCityName
2 | Coconuts | 8 | Got
2 | Apples | 4 | Got
3 | Oranges | 2 | Got
1 | Coconuts | 1 | Sto
But i want:
Id | ArticleName | ArticlesAmount | ToCityName
2 | Coconuts | 4 | Got
2 | Apples | 2 | Got
3 | Oranges | 2 | Got
1 | Coconuts | 1 | Sto
Help would be appreciated, and an explanation please :)
Fiddle

Have a look at SQLFiddle
Code:
SELECT distinct r.ID,a.Name as ArticleName,
sum(distinct a.Amount) as ArticlesAmount,
substr(r.City,1,3) as ToCityName
FROM Reservations r
INNER JOIN Articles a
on r.Id = a.ReservationId
WHERE a.Name <> ''
GROUP BY ToCityName,a.ArticleId,a.Name
ORDER BY ToCityName ASC
You want to ensure you sum the amount by the distinct number of times it appears per group.

I had added Articles again to select requested rows again... here is query
SELECT DISTINCT
r.ID,
a.`Name` AS ArticleName,
Articles.Amount,
substr(r.City, 1, 3) AS ToCityName
FROM
Reservations r
INNER JOIN Articles a ON r.Id = a.ReservationId
INNER JOIN Articles ON a.ReservationId = Articles.ReservationId
AND a.ArticleId = Articles.ArticleId
WHERE
a. NAME <> ''
GROUP BY
ToCityName,
a.ArticleId,
a. NAME
ORDER BY
ToCityName ASC

Related

SQL LEFT JOIN not pulling intended data

I have the below tables:
CATEGORIES:
id | name | category_group | cate_type_id
1 | Entertainment | Entertainment | 1
2 | Electricity | Utilities | 8
3 | Water | Utilities | 8
4 | Rent | Living Exp | 6
5 | credit card | Finance | 5
BUDGET-ITEMS:
id | budget_id | cat_id | category_group| budget_yr | budget_01 | budget_02 | ... | budget_12
1 | 1 | 1 | Entertainment | 2022 | 500 | |
2 | 1 | 2 | Utilities | 2022 | 1500 | |
3 | 1 | 3 | Utilities | 2022 | | 250 |
I want to pull all items from Category table with mapping budget columns. Below is my JOIN.
SELECT c.id as base_id,c.name,c.category_type_id, c.category_group as base_group, b.*
FROM category c
LEFT JOIN budget_items b ON c.id = b.category_id
WHERE c.category_type_id NOT IN (5)
ORDER BY c.category_type_id, c.category_group ASC
I expect the below output:
id | budget_id | cat_id | catgroup | budget_yr | budget_01 | budget_02 | ... | budget_12
1 | 1 | 1 | Entertainment | 2022 | 500 | |
2 | 1 | 2 | Utilities | 2022 | 1500 | |
3 | 1 | 3 | Utilities | 2022 | | 250 |
4 | 1 | 4 | Living Exp | 2022 | | |
However, I get like below (truncated base* columns here for space):
id | budget_id | cat_id | catgroup | budget_yr | budget_01 | budget_02 | ... | budget_12
1 | 1 | 1 | Entertainment | 2022 | 500 | |
2 | 1 | 2 | Utilities | 2022 | | 1500 |
3 | 1 | 3 | Utilities | 2022 | | |
4 | 1 | 4 | Living Exp | 2022 | | |
My query looks OK, not sure where it is going wrong. Does anyone see the issue?
Thanks in advance for your kind help.
Edit:
I have truncated some columns for space here. the problem is the values are aligned to different budget columns. I get the columns correctly from the left table.
Edit:
Thanks to everyone who pitched in to help, I finally figured the issue was with my data. The query was actually working fine. This community is amazing.
Not sure what you're doing, but it seems to work as expected for me:
Schema (SQLite v3.30)
CREATE TABLE items (
`id` INTEGER,
`budget_id` INTEGER,
`cat_id` INTEGER,
`catgroup` VARCHAR(13),
`budget_yr` INTEGER,
`budget_01` INTEGER,
`budget_02` INTEGER
);
INSERT INTO items
(`id`, `budget_id`, `cat_id`, `catgroup`, `budget_yr`, `budget_01`, `budget_02`)
VALUES
('1', '1', '1', 'Entertainment', '2022', '500', null),
('2', '1', '2', 'Utilities', '2022', '1500', null),
('3', '1', '3', 'Utilities', '2022', null, '250');
CREATE TABLE cats (
`id` INTEGER,
`name` VARCHAR(13),
`category_group` VARCHAR(13),
`cate_type_id` INTEGER
);
INSERT INTO cats
(`id`, `name`, `category_group`, `cate_type_id`)
VALUES
('1', 'Entertainment', 'Entertainment', '1'),
('2', 'Electricity', 'Utilities', '8'),
('3', 'Water', 'Utilities', '8'),
('4', 'Rent', 'Living Exp', '6'),
('5', 'credit card', 'Finance', '5');
Query
SELECT c.id
, budget_id
, cat_id
, catgroup
, budget_yr
, budget_01
, budget_02
FROM cats c
LEFT JOIN items i ON c.id = i.cat_id
WHERE c.cate_type_id <> 5;
id
budget_id
cat_id
catgroup
budget_yr
budget_01
budget_02
1
1
1
Entertainment
2022
500
2
1
2
Utilities
2022
1500
3
1
3
Utilities
2022
250
4
View on DB Fiddle

Master-Detail show data SQL

I'm working with SQL Server and I have this 3 tables
STUDENTS
| id | student |
-------------
| 1 | Ronald |
| 2 | Jenny |
SCORES
| id | score | period | student |
| 1 | 8 | 1 | 1 |
| 2 | 9 | 2 | 1 |
PERIODS
| id | period |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
And I want a query that returns this result:
| student | score1 | score2 | score3 | score4 |
| Ronald | 8 | 9 | null | null |
| Jenny | null | null | null | null |
As you can see, the number of scores depends of the periods because sometimes it can be 4 o 3 periods.
I don't know if I have the wrong idea or should I make this in the application, but I want some help.
You need to PIVOT your data e.g.
select Y.Student, [1], [2], [3], [4]
from (
select T.Student, P.[Period], S.Score
from Students T
cross join [Periods] P
left join Scores S on S.[Period] = P.id and S.Student = T.id
) X
pivot
(
sum(Score)
for [Period] in ([1],[2],[3],[4])
) Y
Reference: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-20

add and subtract by type

I have a SQLite table payments:
+------+--------+-------+
| user | amount | type |
+------+--------+-------+
| AAA | 100 | plus |
| AAA | 200 | plus |
| AAA | 50 | minus |
| BBB | 100 | plus |
| BBB | 20 | minus |
| BBB | 5 | minus |
| CCC | 200 | plus |
| CCC | 300 | plus |
| CCC | 25 | minus |
I need to calculate the sum with type 'plus' and subtract from it the sum with type 'minus' for each user.
The result table should look like this:
+------+--------+
| user | total |
+------+--------+
| AAA | 250 |
| BBB | 75 |
| CCC | 475 |
I think that my query is terrible, and I need help to improve it:
select user,
(select sum(amount) from payments as TABLE1 WHERE TABLE1.type = 'plus' AND
TABLE1.user= TABLE3.user) -
(select sum(amount) from payments as TABLE2 WHERE TABLE2.type = 'minus' AND
TABLE2.user= TABLE3.user) as total
from payments as TABLE3
group by client
order by id asc
The type is easier handled with a CASE expression. And then you can merge the aggregation into the outer query:
SELECT user,
SUM(CASE type
WHEN 'plus' THEN amount
WHEN 'minus' THEN -amount
END) AS total
FROM payments
GROUP BY client
ORDER BY id;

SQLite - Update a column based on values from two other tables' columns

I am trying to update Data1's ID to Record2's ID when:
Record1's and Record2's Name are the same, and
Weight is greater in Record2.
Record1
| ID | Weight | Name |
|----|--------|------|
| 1 | 10 | a |
| 2 | 10 | b |
| 3 | 10 | c |
Record2
| ID | Weight | Name |
|----|--------|------|
| 4 | 20 | a |
| 5 | 20 | b |
| 6 | 20 | c |
Data1
| ID | Weight |
|----|--------|
| 4 | 40 |
| 5 | 40 |
I have tried the following SQLite query:
update data1
set id =
(select record2.id
from record2,record1
where record1.name=record2.name
and record1.weight<record2.weight)
where id in
(select record1.id
from record1, record2
where record1.name=record2.name
and record1.weight<record2.weight)
Using the above query Data1's id is updated to 4 for all records.
NOTE: Record1's ID is the foreign key for Data1.
For the given data set the following seems to serve the cause:
update data1
set id =
(select record2.id
from record2,record1
where
data1.id = record1.id
and record1.name=record2.name
and record1.weight<record2.weight)
where id in
(select record1.id
from record1, record2
where
record1.id in (select id from data1)
and record1.name=record2.name
and record1.weight<record2.weight)
;
See it in action: SQL Fiddle.
Please comment if and as this requires adjustment / further detail.

Query returning incorrect count

I have the following query.
SELECT a.link_field1 AS journo, count(a.link_id) as articles, AVG( b.vote_value ) AS score FROM dan_links a LEFT JOIN dan_votes b ON link_id = vote_link_id WHERE link_field1 <> '' and link_status NOT IN ('discard', 'spam', 'page') GROUP BY link_field1 ORDER BY link_field1, link_id
This query is returning a count of 3 for the first item in the list. What should be returned is
Journo | count | score
John S | 2 | 6.00
Joe B | 1 | 4
However for the first one John S, it returns a count of 3.
If I directly query
select * from dan_links where link_field1 = 'John S'
I get 2 records return as I would expect. I can't for the life of me figure out why the count is wrong, unless for some reason it is counting the records from the dan_vote table
How can I get the correct count, or is my query completely wrong?
EDIT: Contents of the tables
dan_links
link_id | link_field1 | link | source | link_status
1 | John S | http://test.com | test.com | approved
2 | John S | http://google.com | google | approved
3 | Joe B | http://facebook.com | facebook | approved
dan_votes
vote_id | link_id | vote_value
1 | 1 | 5
2 | 1 | 8
3 | 2 | 4
4 | 3 | 1
EDIT: it looks like it is counting the rows in the votes table for some reason
When you are doing a left outer join with the condition link_id = vote_link_id for every matching record one row is created, some thing like
link_id | link_field1 | link | source | link_status|vote_id|vote_value
1 | John S | http://test.com | test.com | approved|1|5
1 | John S | http://test.com | test.com | approved|2|8
2 | John S | http://google.com | google | approved|3|4
3 | Joe B | http://facebook.com | facebook | approved|4|1
Now when you do group by on link_field1, you get count as 3 for John S
Nested query might work
SELECT journo,count(linkid) as articles,AVG(score) FROM
(SELECT a.link_field1 AS journo, AVG( b.vote_value ) AS score, a.link_id as linkid
FROM dan_links a
LEFT JOIN dan_votes b
ON link_id = vote_link_id
WHERE link_field1 <> ''
and link_status NOT IN ('discard', 'spam', 'page')
GROUP BY link_id
ORDER BY link_field1, link_id) GROUP BY journo
The above query will give incorrect average as ((n1+n2)/2+n3)/2 != (n1+n2+n3)/3, so use the below query
SELECT journo,count(linkid) as articles, SUM(vote_sum)/SUM(count(linkid))
FROM
(SELECT a.link_field1 AS journo, SUM( b.vote_value ) AS vote_sum, a.link_id as linkid, count(a.link_id) as count_on_id
FROM dan_links a
LEFT JOIN dan_votes b
ON link_id = vote_link_id
WHERE link_field1 <> ''
and link_status NOT IN ('discard', 'spam', 'page')
GROUP BY link_id
ORDER BY link_field1, link_id) GROUP BY journo
Hope this helps.

Resources