Get properly data - city and province count - sql

Structure of the table:
ID | firm | city | province
1 | test1 | Warszawa | 1
2 | test2 | Gdańsk | 12
3 | test3 | Otwock | 1
3 | test4 | Kraków | 3
4 | test5 | Olkusz | 3
This is my SQL query:
SELECT COUNT(miasto) AS cntcity, wojewodztwo, miasto FROM tabela GROUP BY wojewodztwo, miasto ORDER BY wojewodztwo
The result is:
cnt_city | province | city
6 1 Warszawa
2 1 Otwock
3 5 Kraków
7 5 Olkusz
3 12 Gdańsk
I want count "cnt_city" too, or rather SUM "cnt_city" - 6+2 = 8, 3+7=10,3 I Know how to do this in PHP, but it is possible to do it in SQL? How modify above SQL query?
I want result like this:
cnt_city | province | city | cnt_firm
6 1 Warszawa | 8
2 1 Otwock | 8
3 5 Kraków | 10
7 5 Olkusz | 10
3 12 Gdańsk | 3

Use Window Function
SELECT cntcity,
province,
city,
Sum(cntcity)OVER(partition BY province) As cnt_firm
FROM (SELECT Count(miasto) AS cntcity,
province,
city to
FROM tabela
GROUP BY wojewodztwo,
miasto) a

Related

How to build an intercalated ranking from two tables using BigQuery

I have two tables in BigQuery with records ordered by a ranking. Given a ratio of integers, I want to be able to join both tables, keeping the order of the ranking and the proportions of the ratio of integers.
For example:
Table A
Name
Ranking A
Kevin
1
Jack
2
Kate
3
Randall
4
Beck
5
Table B:
Name
Ranking B
William
1
Laurel
2
Sophie
3
Tess
4
Deja
5
Toby
6
Nick
7
Given a ratio 2:3 where 2 corresponds with Table A, and 3 corresponds with Table B, the expected result would be:
Name
Ranking A
Ranking B
Final Rank
Kevin
1
1
Jack
2
2
William
1
3
Laurel
2
4
Sophie
3
5
Kate
3
6
Randall
4
7
Tess
4
8
Deja
5
9
Toby
6
10
Beck
5
11
Nick
7
12
Any ideas?
You can solve this problem with some math trick here. In both tables you have to compute a running sum and skip 2 (for second table) or 3 (for first table) values according to the ranking value you're currently placing. Basically you're making two gapped running sum, where the gaps will be filled by the other one's ranking values.
SELECT Name,
SUM(CASE WHEN MOD(RankingA,2) = 1 THEN 4 ELSE 1 END) OVER(ORDER BY RankingA)-3 AS rn
FROM tableA
UNION ALL
SELECT Name,
SUM(CASE WHEN MOD(RankingB,3) = 1 THEN 3 ELSE 1 END) OVER(ORDER BY RankingB) AS rn
FROM tableB
ORDER BY rn
Then you just apply the UNION ALL operation and ORDER BY on the just generated ranking.
Another approach would be:
SELECT name,
IF(tbl = 1, rank, NULL) AS rankingA,
IF(tbl = 2, rank, NULL) AS rankingB,
ROW_NUMBER() OVER (ORDER BY rank_grp, tbl, rank) final_rank
FROM (
SELECT name, rankingA AS rank, DIV(rankingA - 1, 2) AS rank_grp, 1 AS tbl FROM tableA
UNION ALL
SELECT name, rankingB, DIV(rankingB - 1, 3), 2 FROM tableB
);
+---------+----------+----------+------------+
| name | rankingA | rankingB | final_rank |
+---------+----------+----------+------------+
| Kevin | 1 | | 1 |
| Jack | 2 | | 2 |
| William | | 1 | 3 |
| Laurel | | 2 | 4 |
| Sophie | | 3 | 5 |
| Kate | 3 | | 6 |
| Randall | 4 | | 7 |
| Tess | | 4 | 8 |
| Deja | | 5 | 9 |
| Toby | | 6 | 10 |
| Beck | 5 | | 11 |
| Nick | | 7 | 12 |
+---------+----------+----------+------------+
You may try the following:
select Name, RankingA, RankingB,
rank() over (order by NewRank) FinalRank
from
(
select Name, cast(RankingA as string) as RankingA , '' as RankingB,
RankingA + floor((RankingA-1)/2)*3 as NewRank
from TableA
union all
select Name, '', cast(RankingB as string),
RankingB + ceiling((RankingB)/3)*2
from TableB
) T
RankingA + floor((RankingA-1)/2)*3: shifts each two consecutive RankingA values (1,2 and 3,4 and 5,6 ...) by n * 3 where n starts from 0.
RankingB + ceiling((RankingB)/3)*2: shifts each three consecutive RankingB values (1,2,3 and 4,5,6 ...) by n * 2 where n starts from 1.

How do you use two aggregate functions for separate tables in a join?

Sorry if this is a noob question!
I have two tables - a movie and a comment table.
I am trying to return output of the movie name and each comment for that movie as long as that movie has more than 1 comment associated to it.
Here are my tables
test_movies=# SELECT * FROM movie;
id | name | rating | release_date | original_copy_location
----+------------------------------------+--------+--------------+------------------------
1 | Cruella | 9 | 2021-05-28 | 4
7 | Shutter Island | 9 | 2010-02-19 | 4
9 | Grown Ups | 7 | 2010-06-25 | 4
11 | Guardians of the Galaxy: Volume 1 | 8 | 2014-09-01 | 4
14 | The RIng | 8 | 2002-10-18 | 4
17 | Digimon: The Movie | 6 | 2000-01-10 | 4
19 | Star Wars Episode 1 | 5 | 1999-06-21 | 4
20 | Ghosts Of Mars | 5 | 1998-09-15 | 4
5 | Interstellar | 8 | 2014-11-07 | 1
10 | Mean Girls | 8 | 2004-04-30 | 1
12 | Captain America: The First Avenger | 7 | 2011-07-22 | 1
15 | Get Out | 6 | 2017-02-24 | 1
6 | The Dark Knight | 10 | 2008-07-18 | 2
16 | Pokemon: The First Movie | 5 | 1998-11-10 | 2
18 | The Last Dance | 8 | 2020-05-01 | 2
8 | Just Go With It | 8 | 2011-02-11 | 3
13 | The Blair Witch Project | 8 | 1999-08-29 | 3
(17 rows)
test_movies=# SELECT * FROM comments;
c_id | c_comment | c_movie | c_user
------+--------------------------------------+---------+--------
1 | testing comment 1 | 16 | 4
2 | testing comment 1 | 1 | 1
3 | testing comment 1 | 1 | 2
4 | testing comment 1 | 8 | 5
5 | testing comment 1 | 6 | 3
6 | testing comment 1 | 12 | 2
7 | testing comment 1 | 20 | 3
8 | testing comment 1 | 16 | 5
9 | testing comment 1 | 17 | 4
10 | testing comment 1 | 12 | 2
(10 rows)
Output im trying to get is this:
name | c_comment
------------------------+-------------------------------------
Cruella | testing comment 1
Curella | testing comment 1
Pokemon:The First Movie | testing comment 1
Pokemon:The First Movie | testing comment 1
Captain America | testing comment 1
Captain America | testing comment 1
The problem with my queries is that I can't figure out how to return both the movie name and comment associated with it using aggregate functions.
If I use the count in the first select statement it returns all rows:
SELECT m.name, c.c_comment FROM movie m, comments c WHERE m.id = c.c_movie GROUP BY m.name, c.c_comment HAVING COUNT(m.name) >= 1;
If I try the below subquery I get the error - ERROR: subquery must return only one column
SELECT m.name, c.c_comment FROM movie m, comments c WHERE m.id = c.c_movie AND(SELECT m.name, COUNT(c.c_movie) FROM movie m, comments c WHERE m.id =c.c_movie GROUP BY name HAVING COUNT(c.c_movie) > 1);
Still a bit new to SQL as I'm a student and having a tough time figuring this query out lol.
Thanks in advance!
Something like this could work
select m.name, c.c_comment
from movie m
join comment c
on c.c_movie = m.id
where exists (select 1 from comments cc where cc.c_movie=m.id group by c_movie having count(*)>1)
It's standard sql, but you cannot work with mysql and postgresql at the same time... 🤔
Use window functions!
select m.name, c.c_comment
from movie m join
(select c.*, count(*) over (partition by c_movie) as cnt
from comment c
) c
on c.c_movie = m.id
where cnt > 1;

Generate 'average' column from sub query and ROW_NUMBER window function in SQL SELECT

I have the following SQL Server tables (with sample data):
Questionnaire
id | coachNodeId | youngPersonNodeId | complete
1 | 12 | 678 | 1
2 | 12 | 52 | 1
3 | 30 | 99 | 1
4 | 12 | 678 | 1
5 | 12 | 678 | 1
6 | 30 | 99 | 1
7 | 12 | 52 | 1
8 | 30 | 102 | 1
Answer
id | questionnaireId | score
1 | 1 | 1
2 | 2 | 3
3 | 2 | 2
4 | 2 | 5
5 | 3 | 5
6 | 4 | 5
7 | 4 | 3
8 | 5 | 4
9 | 6 | 1
10 | 6 | 3
11 | 7 | 5
12 | 8 | 5
ContentNode
id | text
12 | Zak
30 | Phil
52 | Jane
99 | Ali
102 | Ed
678 | Chris
I have the following T-SQL query:
SELECT
Questionnaire.id AS questionnaireId,
coachNodeId AS coachNodeId,
coachNode.[text] AS coachName,
youngPersonNodeId AS youngPersonNodeId,
youngPersonNode.[text] AS youngPersonName,
ROW_NUMBER() OVER (PARTITION BY Questionnaire.coachNodeId, Questionnaire.youngPersonNodeId ORDER BY Questionnaire.id) AS questionnaireNumber,
score = (SELECT AVG(score) FROM Answer WHERE Answer.questionnaireId = Questionnaire.id)
FROM
Questionnaire
LEFT JOIN
ContentNode AS coachNode ON Questionnaire.coachNodeId = coachNode.id
LEFT JOIN
ContentNode AS youngPersonNode ON Questionnaire.youngPersonNodeId = youngPersonNode.id
WHERE
(complete = 1)
ORDER BY
coachNodeId, youngPersonNodeId
This query outputs the following example data:
questionnaireId | coachNodeId | coachName | youngPersonNodeId | youngPersonName | questionnaireNumber | score
1 | 12 | Zak | 678 | Chris | 1 | 1
2 | 12 | Zak | 52 | Jane | 1 | 3
3 | 30 | Phil | 99 | Ali | 1 | 5
4 | 12 | Zak | 678 | Chris | 2 | 4
5 | 12 | Zak | 678 | Chris | 3 | 4
6 | 30 | Phil | 99 | Ali | 2 | 2
7 | 12 | Zak | 52 | Jane | 2 | 5
8 | 30 | Phil | 102 | Ed | 1 | 5
To explain what's happening here… There are various coaches whose job is to undertake questionnaires with various young people, and log the scores. A coach might, at a later date, repeat the questionnaire with the same young person several times, hoping that they get a better score. The ultimate goal of what I'm trying to achieve is that the managers of the coaches want to see how well the coaches are performing, so they'd like to see whether the scores for the questionnaires tend to go up or not. The window function represents a way to establish how many times the questionnaire has been undertaken by the same coach/young person combo.
I need to be able to determine the average score based on the questionnaire number. So for example, the coach 'Zak' logged scores of '1' and '3' for his first questionnaires (where questionnaireNumber = 1) so the average would be 2. For his second questionnaires (where questionnaireNumber = 2) the scores were '3' and '5' so the average would be 4. So in analysing this data we know that over time Zak's questionnaire scores have improved from an average of '2' the first time to an average of '4' the second time.
I feel like the query needs to be grouped by the coachNodeId and questionnaireNumber values so it would output something like this (I've ommitted the questionnaireId, youngPersonNodeId, youngPersonName and score columns as they aren't crucial for the output — they're only used to derive the averageScore — and wouldn't be useful the way the results are grouped):
coachNodeId | coachName | questionnaireNumber | averageScore
12 | Zak | 1 | 2 (calculation: (1 + 3) / 2)
12 | Zak | 2 | 4 (calculation: (3 + 5) / 2)
12 | Zak | 3 | 4 (only one value: 4)
30 | Phil | 1 | 5 (calculation: (5 + 5) / 2)
30 | Phil | 2 | 2 (only one value: 2)
Could anyone suggest how I can modify my query to output the average scores based on the score from the sub-query and the ROW_NUMBER window function? I've hit the limits of my SQL skills!
Many thanks.
It is a bit hard to tell without sample data, but I think you are describing aggregation:
SELECT q.coachNodeId AS coachNodeId,
cn.[text] AS coachName,
q.youngPersonNodeId AS youngPersonNodeId,
ypn.[text] AS youngPersonName,
AVG(score)
FROM Questionnaire q JOIN
ContentNode cn
ON q.coachNodeId = cn.id JOIN
ContentNode ypn
ON q.youngPersonNodeId = ypn.id LEFT JOIN
Answer a
ON a.questionnaireId = q.id
WHERE complete = 1
GROUP BY q.coachNodeID, cn.[text] AS coachName,
q.youngPersonNodeId, ypn.[text]

Sum multiple columns based on criteria from other columns - SQL Teradata

I would like to get a total of the scores from columns 3 & 4 for each of the counties in columns 1 & 2 from the table shown below:
County1 | County2 | Player1_Score | Player2_Score
Norfolk | Hampshire | 5 | 7
Suffolk | Norfolk | 10 | 6
Hampshire | Suffolk | 16 | 12
Norfolk | Suffolk | 78 | 50
Hampshire | Norfolk | 4 | 8
Suffolk | Hampshire | 9 | 19
So the results I would like to see would be as follows:
Norfolk | 97
Suffolk | 77
Hampshire | 32
Can anyone please help with this? I tried a SELECT/GROUP BY query but am fairly new to SQL and couldn't get the results I wanted.
Many thanks
Try this:
SELECT County, SUM(Score) AS TotalScore
FROM (
SELECT County1 AS County, Player1_Score AS Score
FROM mytable
UNION ALL
SELECT County2, Player2_Score
FROM mytable) AS t
GROUP BY County
ORDER BY TotalScore DESC
Demo here
SEL CNTRY,SUM(SUM1) FROM
(
SEL COUNTRY1 AS CNTRY, SUM(player_score_1) AS SUM1 FROM VT1
GROUP BY 1
UNION
SEL COUNTRY2 AS CNTRY, SUM(player_score_2) FROM VT1
GROUP BY 1
) A
GROUP BY 1

Oracle query using 3 tables, sql

I have a problem with a query for Oracle with this scenario:
Table People
ID | Name
1 | juan
2 | pedro
3 | luis
Table Properties
ID | nombre_inmueble | FK to Table People
1 | house | 1
2 | garden | 1
3 | terrace | 1
4 | moto | 2
5 | jet | 2
Table Accessories
ID | accessories | FK Table Properties
1 | windows | 1
2 | doors | 1
3 | scale | 2
4 | plants | 3
5 | motor | 4
What I want is only the people who have Properties and that have ALL Accessories, in this case the output would be
1 | juan
What would be the query?
Your query will look like this:
SELECT *
FROM People P
WHERE EXISTS(
SELECT 1
FROM Properties T
WHERE T.PEOPLE= P.ID
)
AND NOT EXISTS(
SELECT 1
FROM Properties T
WHERE T.PEOPLE= P.ID
AND NOT EXISTS(
SELECT 1
FROM Accessories A
WHERE A.Properties = T.ID
)
);