How to add a condition to count function in PostgreSQL - sql

I have these tables Course, subscription,subscription_Course(A table that creates a relation between Course and subscription), and another with Student. I want to Select all the id_courses that have a subscription count higher than 1 but only want to count the subscriptions from different students. Example: If a Student Subscribes two times the same course I want to have a condition that enables the count function to not count more than one time in these cases
These are my tables:
Student:
idStudent(pk)
cc
nif
1
30348507
232928185
2
30338507
231428185
3
30438507
233528185
4
30323231
3232132
Subscription
idsubscription(pk)
Student(fk)
value_subscription
vouchercurso
date
1
1
100
null
2021-11-01
2
2
150
null
2021-12-11
3
3
160
null
2021-01-03
4
4
500
null
1996-11-07
5
1
900
null
2001-07-05
6
2
432
null
2021-05-09
Subscription_Course
idsubscription(PK/fk)
id_Course(pk/fk)
Grade
1
3
9
2
4
15
3
5
12
6
3
9
5
4
16
2
6
20
6
5
4
For example, when counting within my table Subscription_Course only the id_course:5 would have a count higher than 1 because 3 and 4 have a subscription from the same student.
I have this query for now:
Select id_Course
From Subscription_Course
Group by id_Course
Having Count (id_Course)>1
I don't know what to do to add this condition to the count.

seems like you need to join to Subscription and count unique Student id's:
select id_Course
from Subscription_Course sc
join Subscription s
on s.idsubscription = sc.idsubscription
group by id_Course
having Count(distinct Studentid)>1

You can join the Subscription_Course table with the Subscription table in order to access the id_Student column. Then just count the distinct id_Student values for each id_Course value.
SELECT
Subscription_Course.id_Course,
COUNT(DISTINCT Subscription.id_Student) AS student_count
FROM Subscription_Course
INNER JOIN Subscription
ON Subscription_Course.id_Subscription = Subscription.id_Subscription
GROUP BY Subscription_Course.id_Course
HAVING COUNT(DISTINCT Subscription.id_Student) > 1
ORDER BY student_count DESC;
With result:
id_course | student_count
-----------+---------------
3 | 2
4 | 2
5 | 2

Related

filling running total over all month although its null

I have 2 tables. One only with all periods. Second with Account, Amount and period.
I want to build a View that lists Amount kumulated, period and account. Also if I don't have an fact for a period in my table should be appear the period in my view with the last amount.
select distinct
account, b.periode,
SUM(amount) OVER (PARTITION BY account ORDER BY b.periode RANGE UNBOUNDED PRECEDING)
from
fakten a
full join
perioden b on a.periode = b.periode
order by b.periode
it like this:
1 1 6
2 1 4
1 2 13
2 2 3
NULL 3 NULL
1 4 46
2 5 48
NULL 6 NULL
NULL 7 NULL
1 8 147
NULL 9 NULL
NULL 10 NULL
NULL 11 NULL
NULL 12 NULL
I need it like:
1 1 6
2 1 4
1 2 13
2 2 3
1 3 13
2 3 3
1 4 46
2 4 3
1 5 46
2 5 48
1 6 46
2 6 46
and so one...
Any ideas?
full join is not the right approach. Instead, generate the rows you want using a cross join. Then use left join and group by to do the calculation.
select a.account, p.periode,
SUM(f.amount) OVER (PARTITION BY a.account ORDER BY p.periode)
from (select distinct account from fakten) a cross join -- you probably have an account table, use it
perioden p
on a.periode = p.periode left join
fakten f
on f.account = a.account and f.periode = p.periode
group by a.account, p.periode
order by a.account, p.periode;

Multiply newly entered row with another column value and find Total Sum in SQL

I have 4 tables here, I need to multiply newly entered row value in a table with another row and find the total sum using CustomerId:
CustomerTable:
CustomerId Name EmailId
-------------------------
1 Paul r#r.com
2 John J#j.com
LoyaltyPointTable:
LoyaltyPointsId LoyaltyType Points
---------------------------------------
1 Registration 10
2 Loginstatus 1
3 Downloading 10
4 Redemming 1
5 Sharing 20
6 Refer 10
LoyaltyDetailsTable:
LoyaltyDetailsId LoyaltyPointsId CustomerId Dates
-------------------------------------------------
1 1 1 2015-01-22
2 2 1 2015-01-22
3 3 2 2015-01-22
4 3 1 2015-01-22
5 4 1 2015-01-22
6 4 1 2015-01-24
7 5 1 2015-01-24
This query works fine for the total sum for each LoyaltyType
SELECT
LoayaltyPointsTable.LoyaltyType,
COUNT(CustomerTable.CustomerId) AS UserActions,
SUM(LoayaltyPointsTable.Points) AS TotalPoints
FROM
LoayaltyPointsTable
JOIN
LoyaltyDetailsTable ON LoayaltyPointsTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoayaltyPointsTable.LoyaltyType
below RedeemPointsTable is created with relation to row redeeming in LoyaltyPointTable:
RedeemPointsTable:
RedeemPointsId CustomerId ShopName BillNo Amount
------------------------------------------------
1 1 Mall x 4757 100
3 1 Mall y SH43 50
4 1 Mall x 7743 10
6 1 Mall x s34a 60
What I am expecting is before calculating the total sum, I want column Amount sum (100+50+10+60) * 1 in Redeeming in LoyaltyPointTable to be added with total points for each CustomerId
Expected output
LoyaltyType UserActions TotalPoints
-------------------------------------
Downloading 1 10
Loginstatus 1 1
Redemming 4 (100+50+10+60)*1(here using Amount in RedeemPointsTable)
Refer 1 10
Registration 1 10
Sharing 1 20
User actions count is 4, it is based on the Amount he entered in RedeemPointsTable
Should I need to make changes in adding a foreign key column in RedeemPointsTable or can you point out my mistake?
Any help would be great.
This is the query which returns desired result:
SELECT
LoyaltyPointTable.LoyaltyType,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT COUNT(amount) FROM RedeemPointsTable where CustomerId=1)
ELSE COUNT(CustomerTable.CustomerId)
END as UserActions,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT SUM(amount) FROM RedeemPointsTable where CustomerId=1)*Points
ELSE SUM(LoyaltyPointTable.Points)
END as TotalPoints
FROM
LoyaltyPointTable
JOIN
LoyaltyDetailsTable ON LoyaltyPointTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoyaltyPointTable.LoyaltyType
You can check it here

Selecting rows and filler (null data)

I have a table that looks like this:
ReportID | TeamID | Inning | Runs
1 A 1 3
1 A 2 3
1 A 5 7
1 B 1 3
1 B 3 2
1 B 6 1
I need to select all of that data, plus null data for the missing innings. It also need to stop at the max Inning for both teams (i.e. teamB's highest inning is 6, so I would collect 6 rows for both teamA and teamB yielding 12 total rows.)
For a visual, I need the output of the query to look like this:
ReportID | TeamID | Inning | Runs
1 A 1 3
1 A 2 3
1 A 3 NULL
1 A 4 NULL
1 A 5 7
1 A 6 NULL
1 B 1 3
1 B 2 NULL
1 B 3 2
1 B 4 NULL
1 B 5 NULL
1 B 6 1
Is there anyway to do this with just a query? Modifying the original table to add the null values is not an option.
Self join to generate the permutations of reports and teams
Left self join to generate hits which might be nullable.
This is probably a lot more efficient if it's done outside of SQL
SELECT ins.ReportID, teams.TeamID, ins.inning, score.Runs
FROM games as ins
JOIN games AS teams
ON ins.ReportID = teams.ReportID
LEFT JOIN games AS score
ON ins.ReportID = score.ReportID
AND teams.TeamID = score.TeamID
AND ins.inning = score.inning
GROUP BY ins.ReportID, teams.TeamID, ins.inning;

Query for max to_date for one user id?

I am getting some unexpected results from a SQL query.
Table data:
users:
id username
1 admin
2 x1
3 y1
4 z1
my_connections:
id user_id friend_user_id status
1 1 2 201
2 2 1 201
3 2 4 201
4 1 3 200
5 2 3 201
6 3 2 201
7 4 2 201
8 4 1 200
jobs:
id user_id company_name designation from_date to_date
1 1 A 1 2011-06-01 2011-07-30
2 1 B 11 2011-08-02 2014-01-20
3 2 c 12 2012-05-02 2014-01-20
4 3 D 13 2010-05-02 2014-01-20
5 4 E 11 2009-05-25 2014-01-01
Here is my query:
SELECT users.id,users.username,my_connections.user_id,my_connections.friend_user_id,my_connections.status,jobs.user_id,jobs.company_name,
jobs.designation,jobs.from_date,MAX(jobs.to_date)
FROM users
LEFT JOIN jobs ON jobs.user_id = users.id
LEFT JOIN my_connections ON my_connections.friend_user_id = users.id
WHERE my_connections.status = 201 AND users.id IN (1,3,4)
GROUP BY jobs.company_name
ORDER BY jobs.to_date DESC
And the results:
id username user_id friend_user_id status user_id company_name designs from_date to_date
3 .. 2 3 201 3 D .. 2010-05-02 2014-01-20
4 .. 2 4 201 4 E .. 2009-05-25 2014-01-01
1 .. 2 1 201 1 A .. 2011-08-02 2014-01-20
1 .. 2 1 201 1 B .. 2011-06-01 2011-07-30
In the result, I wanted one row per friend_user_id, with the maximum value of to_date. Instead I am getting multiple rows (if there are multiple rows in the jobs table).
How can I fix this query?
if you want unique results on the friend_user_id field you must group by friend_user_id. This will guarantee unique results on the friend_user_id column. But im pretty sure you don't want that because it may show incorrect data. I am still unsure how the query is working because the group by only contains one field. You must group by all the raw fields in the select query and perform aggregate functions on fields that are not in the group by clause for example:
SELECT users.id,users.username,my_connections.user_id,my_connections.friend_user_id,my_connections.status,jobs.user_id,jobs.company_name,
jobs.designation,jobs.from_date,MAX(jobs.to_date)
FROM users
LEFT JOIN jobs ON jobs.user_id = users.id
LEFT JOIN my_connections ON my_connections.friend_user_id = users.id
WHERE my_connections.status = 201 AND users.id IN (1,3,4)
GROUP BY users.id,users.username,my_connections.user_id,my_connections.friend_user_id,my_connections.status,jobs.user_id,jobs.company_name,
jobs.designation,jobs.from_date
ORDER BY jobs.to_date DESC
In this query all of the fields in the group by clause are in the select clause. Now all the fields not included in the group by clause can use functions like: MAX(), AVG(), SUM() etc.

Need hierarichal data from 3 tables in SQL Server

I have following tables:
UserMaster:
UserId Int, UserName Varchar(200),AddedBy Int
UserId EmpName AddedBy
1 admin 0
2 SubAdmin1 1
3 SubAdmin2 1
4 Vikas 2
5 Mohit 4
6 Atul 5
7 Vishal 6
8 Mani 3
9 Sunny 8
SalesMaster:
SalesId Int, UserId Int (FK_UserMaster_UserId) , Price Int
SalesId UserId Price
1 1 100
2 2 200
3 3 300
4 4 500
5 5 100
6 6 200
7 7 111
8 8 222
9 9 333
Case 1: Now I want the price total of all the users who are under the one particular user and its own price also.
Means If i consider UserId=1 , Then the price will be calculated for all users where Column value in AddedBy=1
and their lower level employees.
Means the total Price of users will be calulated for the users having UserId are: 1,2,3,4,5,6,7,8,9.
Case 2: Similarly, If i want to calculate the total price under UserId=3(SubAdmin2) then the total price from the salesMaster will be calculated for the Users having UserId are: 3,8,9
The Result of first Case should be:
UserId Price
1 2066
The Result of Second Case should be:
UserId Price
3 300+222+333
Please Help
Thanks & Regards
Nitin
with cte as (
select #UserId as UserId
union all
select um.UserId
from UserMaster as um
inner join cte as c on c.UserId = um.AddedBy
)
select sum(s.Price)
from cte as c
inner join SalesMaster as s on s.UserId = c.UserId
sql fiddle demo