Combine the data of two tables using SQL Pivot and joins for a subquery - sql

I'm trying to create a report to find the number of users subscribed to the notification type.
I am stuck with subqueries because if these two tables
Table 1
NotificationMaster
+----+-------+
| ID | Name |
+----+-------+
| 1 | Email |
| 2 | Push |
| 3 | Call |
+----+-------+
Table 2
NotificationPreference
+------------+------------------+------------+--------------+
| ResourceID | NotificationID | IsChecked | AccountID |
+------------+------------------+------------+--------------+
| 23 | 1 | 1 1 |
| 36 | 2 | 0 2 |
| 45 | 3 | 1 3 |
| 23 | 1 | 0 1 |
| 36 | 2 | 1 2 |
| 45 | 3 | 0 3 |
| 23 | 1 | 1 1 |
| 36 | 2 | 0 3 |
| 45 | 3 | 1 3 |
+------------+------------------+--------------------------+
Expected Output
Notification Vs Resource Count
+----------+-------+------+------+
| Accountid Email | Push | Call |
+----------+-------+------+------+
| 1 | 2 | 1 | 2 |
+----------+-------+------+------+
Other Tables
AccountName
+----+-------+
| ID | Name |
+----+-------+
| 1 | Blues |
+----+-------+
| 2 | Jazz |
+----+-------+
| 3 | Rock |
+----+-------+
ResourceNames
+----------+----------------+-----------+
| Resource | Name | AccountID |
+----------+----------------+-----------+
| 23 | MJ | 1 |
| 36 | Paul | 1 |
| 45 | Jay Z | 3 |
+----------+----------------+-----------+
Progress Till Now
SELECT A.ID
,A.Name
,count(R.id) AS 'Total Resource Count'
,(SELECT count(DISTINCT np.resourceid)
FROM NotificationPreference np
INNER JOIN NotificationMaster nm ON np.notificationid = nm.id
WHERE np.accountid = A.ID
AND nm.id = 1
) AS 'Email'
FROM AccountName A
LEFT JOIN [ResourceNames] R ON A.ID = R.[AccountID]
LEFT JOIN NotificationPreference np ON np.resourceid = R.ID
GROUP BY A.ID
,A.Name

The basic pivot use conditional COUNT() :
SELECT Accountid
, COUNT( CASE WHEN nm.Name = 'Email' THEN 1 END ) as Email
, COUNT( CASE WHEN nm.Name = 'Push' THEN 1 END ) as Push
, COUNT( CASE WHEN nm.Name = 'Call' THEN 1 END ) as Call
FROM NotificationPreference np
JOIN NotificationMaster nm
ON np.NotificationID = nm.id
GROUP BY Accountid

Related

How to assign duplicate increment in SQL?

While going through SQL columns, if we find text match "NEW" in Calc column, update the incrementing a count starting with 1 in Results column.
It should look like this on the output:
The following uses an id column to resolve the order issue. Replace that with your corresponding expression. This also addresses the requirement to start the display sequence with 1 and also show 0 for the 'NEW' rows.
The SQL (updated):
SELECT logs.*
, CASE WHEN text = 'NEW' THEN 0
ELSE
COALESCE(SUM(CASE WHEN text = 'NEW' THEN 1 END) OVER (PARTITION BY xrank ORDER BY id)+1, 1)
END AS display
FROM logs
ORDER BY id
The result:
+----+-------+------+---------+
| id | xrank | text | display |
+----+-------+------+---------+
| 1 | 1 | A | 1 |
| 2 | 1 | B | 1 |
| 3 | 1 | C | 1 |
| 4 | 1 | NEW | 0 |
| 5 | 1 | D | 2 |
| 6 | 1 | Q | 2 |
| 7 | 1 | B | 2 |
| 8 | 1 | NEW | 0 |
| 9 | 1 | D | 3 |
| 10 | 1 | Z | 3 |
| 11 | 2 | A | 1 |
| 12 | 2 | B | 1 |
| 13 | 2 | C | 1 |
| 14 | 2 | NEW | 0 |
| 15 | 2 | D | 2 |
| 16 | 2 | Q | 2 |
| 17 | 2 | B | 2 |
| 18 | 2 | NEW | 0 |
| 19 | 2 | D | 3 |
| 20 | 2 | Z | 3 |
+----+-------+------+---------+
You need a column that specifies the ordering for the table. With that, just use a cumulative sum:
select t.*,
1 + sum(case when Calc = 'NEW' then 1 else 0 end) over (partition by Rank_Id order by Seq) as display
from t;

Use information cells instead of column heads

I had trouble reporting information and building View
My table information is as follows
DataBase
Table Stu
---------------------------------------------------
----------------------< Stu >----------------------
---------------------------------------------------
| id | name | age|id_Orientation | id_StudyStatus|
---------------------------------------------------
| 1 | John | 24 | 1 | 1 |
| 2 | Sara | 23 | 1 | 2 |
| 3 | Mary | 26 | 1 | 3 |
| 4 | Jax | 25 | 2 | 1 |
| 5 | izable| 22 | 2 | 2 |
| 6 | Tari | 23 | 2 | 3 |
| 7 | Kap | 26 | 3 | 1 |
| 8 | Lio | 25 | 3 | 2 |
| 9 | Soti | 22 | 3 | 3 |
---------------------------------------------------
Table StudyStatus
-----------------
--<StudyStatus>--
-----------------
| id | name |
-----------------
| 1 | Studying |
| 2 | Cancel |
| 3 |laying off|
-----------------
Table Orientation
-------------------
---<Orientation>---
-------------------
| id | name |
-------------------
| 1 | IT |
| 2 |Construction|
| 3 | Medical |
-------------------
[The output I finally want]
----------------------------------------------------------
----------------------< Stu >------------------------------
-----------------------------------------------------------
| id | name | All | Studying | Cancel | layingOff |
---------------------------------------------------
| 1 | IT | 3 | 1 | 1 | 1 |
| 2 |Construction| 3 | 1 | 1 | 1 |
| 3 | Medical | 3 | 1 | 1 | 1 |
-----------------------------------------------------------
By What Query ?
Please Help ... !
Thanks
Try it. but first remove the Blank Space of Left & Right Side from the Name of StudyStatus.
select isnull([Studying],0)+isnull([Cancel],0)+isnull([Laying off],0) [All], Orientation_Name,[Studying],[Cancel],[Laying off]
from
(
select s.id,o.Name Orientation_Name ,ss.Name StudyStatus_Name
from Stu s inner join StudyStatus ss on s.ID_StudyStatus=ss.ID inner join Orientation O on o.Id=s.ID_Orientation)as st
pivot
(
count(id)
FOR StudyStatus_Name IN ([Studying],[Cancel],[laying off])
) as PV
You can go for conditional sum and get the results.
SELECT o.name,
COUNT(*) AS All,
SUM(CASE WHEN ss.Name = 'Studying' THEN 1 ELSE 0 END) AS Studying,
SUM(CASE WHEN ss.Name = 'Cancel' THEN 1 ELSE 0 END) AS cancel,
SUM(CASE WHEN ss.Name = 'Laying Off' THEN 1 ELSE 0 END) AS LayingOff
FROM Orientation as o
inner join Stu as s
on s.id_orientation = s.id
inner join StudyStatus AS ss
on ss.id = s.id_StudyStatus
GROUP BY o.name
select isnull([Studying], 0) + isnull([Cancel], 0) + isnull([laying off], 0) [All],
Orientation_Name,
[Studying],
[Cancel],
[laying off]
from (
select s.id,
o.name Orientation_Name,
ss.name StudyStatus_Name
from Stu s
inner join StudyStatus ss on ss.id = s.id_StudyStatus
inner join Orientation o on o.id = s.id_Orientation
) as st pivot (
count(id) FOR StudyStatus_Name IN ([Studying], [Cancel], [laying off])
) as PV
Pay attention to uppercase and lowercase letters Move Inner Join
Thanks to #LiaqatKundi and #DaleK

How to handle multiple rows fulfilling criteria when joining Oracle tables

Given a table of roles, companies and a employee table where we store for each employee which role he/she has at each company.
I'm trying to create a view which indicates for each combination of role and company and employee by a ‘Y’ or ‘N’ in the “checked_yn” column, whether this employee has this role at this company.
company table
----------------
|ID | name |
-----------------
| 1 | A |
| 2 | B |
-----------------
roles table
-------------
|ID | role |
-------------
| 1 | X |
| 2 | Y |
| 3 | Z |
-------------
employee table
----------------------------------------------
|ID | company_id | role_id | employee_log_id |
---------------------------------------------|
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 |
| 3 | 2 | null | 1 |
----------------------------------------------
The desired outcome is this:
EMPLOYEE_ROLES_VW view
------------------------------------------------------------------------
|Id |company_id | role_id | Checked_yn | employee_id | employee_log_id |
|----------------------------------------------------------------------|
| 1 | 1 | 1 | Y | 1 | 1 |
| 2 | 1 | 2 | Y | 2 | 1 |
| 3 | 1 | 3 | N | null | 1 |
| 4 | 2 | 1 | N | null | 1 |
| 5 | 2 | 2 | N | null | 1 |
| 6 | 2 | 3 | N | null | 1 |
------------------------------------------------------------------------
This is my current query:
with ROLES_X_COMP as (SELECT ROL.ID AS X_ROLE_ID,
COM.ID AS X_COMPANY_ID,
FROM ROLES ROL
CROSS JOIN COMPANY COM)
SELECT ROWNUM AS ID,
EMP.ID AS SMCR_EMPLOYEE_ID,
EMP.EMPLOYEE_LOG_ID AS EMPLOYEE_LOG_ID,
ROLES_X_COMP.X_ROLE_ID ,
EMP.ROLE_ID AS ROLE_ID,
ROLES_X_COMP.X_COMPANY_ID,
EMP.COMPANY_ID AS COMPANY_ID,
CASE
WHEN ROLES_X_COMP.X_ROLE_ID = SE.ROLE_ID AND ROLES_X_COMP.X_COMPANY_ID =
SE.COMPANY_ID THEN 'Y'
ELSE 'N' END AS CHECKED_YN
FROM ROLES_X_COMP
LEFT OUTER JOIN EMPLOYEE EMP ON ROLES_X_COMP.X_COMPANY_ID = EMP.COMPANY_ID
Because of the join on EMPLOYEE “finds” the company with id=1 twice it joins twice with the cross join of role and company table. So I'm getting this result:
------------------------------------------------------------------------
|Id |company_id | role_id | Checked_yn | employee_id | employee_log_id |
|----------------------------------------------------------------------|
| 1 | 1 | 1 | Y | 1 | 1 |
| 2 | 1 | 2 | N | 1 | 1 |
| 3 | 1 | 3 | N | 1 | 1 |
| 4 | 1 | 1 | N | 2 | 1 |
| 5 | 1 | 2 | Y | 2 | 1 |
| 6 | 1 | 3 | N | 2 | 1 |
| 7 | 2 | 1 | N | 3 | 1 |
| 8 | 2 | 2 | N | 3 | 1 |
| 9 | 2 | 3 | N | 3 | 1 |
------------------------------------------------------------------------
I think a JOIN might be the wrong option here and a UNION more appropriate but I can't figure it out.
Use a partitioned outer join:
Query:
SELECT ROWNUM AS id,
e.company_id,
r.id AS role_id,
NVL2( e.role_id, 'Y', 'N' ) AS CheckedYN,
e.role_id AS employee_id,
e.employee_log_id
FROM roles r
LEFT OUTER JOIN
employee e
PARTITION BY ( e.company_id, e.employee_log_id )
ON ( r.id = e.role_id )
or (depending on how you want to partition and join the data):
SELECT ROWNUM AS id,
c.id AS company_id,
r.id AS role_id,
NVL2( e.role_id, 'Y', 'N' ) AS CheckedYN,
e.role_id AS employee_id,
e.employee_log_id
FROM roles r
CROSS JOIN
company c
LEFT OUTER JOIN
employee e
PARTITION BY ( e.employee_log_id )
ON ( c.id = e.company_id AND r.id = e.role_id )
Output:
Both output the same for the test data but may give differing results depending on your actual data.
ID | COMPANY_ID | ROLE_ID | CHECKEDYN | EMPLOYEE_ID | EMPLOYEE_LOG_ID
-: | ---------: | ------: | :-------- | ----------: | --------------:
1 | 1 | 1 | Y | 1 | 1
2 | 1 | 2 | Y | 2 | 1
3 | 1 | 3 | N | null | 1
4 | 2 | 1 | N | null | 1
5 | 2 | 2 | N | null | 1
6 | 2 | 3 | N | null | 1
db<>fiddle here
AND ROLES_X_COMP.X_ROLE_ID = EMP.ROLE_ID
Is missing at the end of your query
But the outcome will be
EMPLOYEE_ROLES_VW view
------------------------------------------------------------------------
|Id |company_id | role_id | Checked_yn | employee_id | employee_log_id |
|----------------------------------------------------------------------|
| 1 | 1 | 1 | Y | 1 | 1 |
| 2 | 1 | 2 | Y | 2 | 1 |
| 3 | 1 | 3 | N | null | null |
| 4 | 2 | 1 | N | null | null |
| 5 | 2 | 2 | N | null | null |
| 6 | 2 | 3 | N | null | null |
------------------------------------------------------------------------

SQL - How to avoid the joining of three queries into one

I have a SQL script that selects assignments that a student has been assigned. In order to find out if the student completed his assignment, i use a sub-query. Once the student finishes an assignment he should be able to work on the next one.
I figure I can do this by selected the top 1 assignment that has not been completed ( 0 value). Which I can do with an additional query, of the first query, but then i would need a third query to join that query together. Is there a way i can achieve this selection of the top 1 assignment that has a value of 0, with 2 queries or less?
First Attempt
SELECT ag.group_id,
ag.title,
ac.collection_id,
ag.order,
ac.NAME,
ac.isactive,
(SELECT top 1 iscompleted
FROM student_completion
WHERE fk_collection_id = collection_id
AND fk_student_id like '404')
AS isCompleted,
FROM assignments AS ag
JOIN assignments_collection AS ac
ON ag.fk_collection_id = ac.collection_id
Order BY group_id
/*
SELECT TOP 1 isCompleted
(SELECT ag.group_id,
ag.title,
ac.collection_id,
ag.order,
ac.NAME,
ac.isactive,
(SELECT top 1 iscompleted
FROM student_completion
WHERE fk_collection_id = collection_id
AND fk_student_id like '404')
AS isCompleted,
FROM assignments AS ag
JOIN assignments_collection AS ac
ON ag.fk_collection_id = ac.collection_id
Order BY group_id)
Where isCompleted = 0
.........
*/
Data
+----------+--------------+---------------+-------+----------------------+----------+-------------+
| group_id | title | collection_id | order | name | isactive | isCompleted |
+----------+--------------+---------------+-------+----------------------+----------+-------------+
| 1 | Assingment_1 | 5 | 0 | Welcome to Linux | 1 | 0 |
| 2 | Assingment_2 | 6 | 0 | Installation | 1 | 0 |
| 3 | Assingment_3 | 9 | 1 | Intro to Bash | 1 | 0 |
| 3 | Assingment_4 | 3 | 1 | Intro to Bash part 2 | 1 | 0 |
+----------+--------------+---------------+-------+----------------------+----------+-------------+
Expected Data
+----------+--------------+---------------+-------+----------------------+----------+-------------+-----------+
| group_id | title | collection_id | order | name | isactive | isCompleted | available |
+----------+--------------+---------------+-------+----------------------+----------+-------------+-----------+
| 1 | Assingment_1 | 5 | 0 | Welcome to Linux | 1 | 0 | 1 |
| 2 | Assingment_2 | 6 | 0 | Installation | 1 | 0 | 0 |
| 3 | Assingment_3 | 9 | 1 | Intro to Bash | 1 | 0 | 0 |
| 3 | Assingment_4 | 3 | 1 | Intro to Bash part 2 | 1 | 0 | 0 |
+----------+--------------+---------------+-------+----------------------+----------+-------------+-----------+
student_completion
+---------------+------------------+-------------+
| FK_studentKey | FK_collectionKey | isCompleted |
+---------------+------------------+-------------+
| 404 | 5 | 1 |
+---------------+------------------+-------------+
Your question is extremely lacking in explanation. I am taking a shot in the dark here. Does this do what you want?
select d.*
, available = sc.isCompleted
from Data d
left join student_completion sc on sc.FK_colletionKey = d.collection_id

SQL select from 3 table

I have 3 tables:
ssu:
id (primary key)
ssu_number
agreement:
agreement_id
agreement_number
agreement_status_fk
agreement_type_fk
agreement_ssu:
ssu_id
agreement_fk
I need to select ssu_number which occur at least 2 times as ssu_id in table agreement_ssu, which have agreement_status_fk = 1 and agreement_type_fk = 1.
Here is my select but i think it will be not work (i cant test it now):
select
*
from
asd.ssu p
join tdd.agreement_ssu ap on p.id = ap.ssu
join tdd.agreement ae on ae.id = ap.AGREEMENT_FK
join
(
select
ssu_id
from
tdd.agreement_ssu
group by
ssu_ID
having
count( ssu_id ) > 1 )
y on y.ssu_id = p.ID
where
ae.AGREEMENT_TYPE_FK = 1
and
ae.agreement_status_fk = 1;
Example
ssu
| id | ssu_number|
| 1 | 2000 |
| 2 | 2001 |
| 3 | 2002 |
| 4 | 2003 |
agreement
| agreement_id | agreement_number | agreement_status_fk | agreement_type_fk |
| 1 | da5as6d | 1 | 1 |
| 2 | d57as6 | 1 | 2 |
| 3 | dsjks6d | 2 | 2 |
| 4 | d4s7sad | 1 | 1 |
| 5 | d43790d | 1 | 1 |
| 6 | d437s6d | 1 | 1 |
| 7 | d4aq36d | 1 | 2 |
agreement_ssu
| ssu_id | agreement_fk |
| 1 | 1 |
| 1 | 2 |
| 2 | 6 |
| 2 | 4 |
| 2 | 7 |
| 3 | 3 |
| 4 | 5 |
And from select i should get only ssu_number: 2001 (occurs 2 times in agreement_ssu and both have agreement_status_fk = 1 and agreement_type_fk = 1)
| ssu_number |
| 2001 |
I have not setup the exact scenario, and not checked this code, but I think something along these lines is what you want:
SELECT
ssu.ssu_number
FROM
ssu
INNER JOIN
(
SELECT
assu.ssu_id
FROM
agreement_ssu assu
INNER JOIN
agreement a on a.agreement_id = assu.agreement_fk
GROUP BY
assu.ssu_id
WHERE
a.agreement_status_fk = 1
AND a.agreement_type_fk = 1
HAVING
COUNT(assu.ssu_id) > 1
) IT ON ssu.id = IT.ssu_id
Regards...
This should do it,
SELECT SSU.SSU_NUMBER
FROM SSU
JOIN AGREEMENT_SSU
ON SSU.ID = AGREEMENT_SSU.SSU_ID
JOIN AGREEMENT
ON AGREEMENT.ID = AGREEMENT_SSU.AGREEMENT_FK
WHERE AGREEMENT.AGREEMENT_STATUS_FK = 1
AND AGREEMENT.AGREEMENT_TYPE_FK = 1
GROUP BY SSU.SSU_NUMBER
HAVING COUNT(*) > 1;