Moodle - configurable reports query scorm? - sql

i hope someone can help me :)
I need a query to get user name | scorm module name | module start date | module completition date | (optional) total_time
My query for now is this but i'm not so good with postgresql :(
SELECT
u.firstname AS First,
u.lastname AS Last,
sc.name AS Modulo,
st.value AS Status,
'' AS Inizio,
TO_CHAR(TO_TIMESTAMP(st.timemodified), 'DD/MM/YYYY HH24:MI') AS Completamento
FROM prefix_scorm_scoes_track AS st
JOIN prefix_user AS u ON st.userid=u.id
JOIN prefix_user_info_data AS uid ON uid.userid = u.id
JOIN prefix_scorm AS sc ON sc.id=st.scormid
JOIN prefix_course AS c ON c.id=sc.course
JOIN prefix_groups AS g ON g.courseid = c.id
JOIN prefix_groups_members AS m ON g.id = m.groupid
WHERE (st.element='cmi.core.lesson_status' and st.value = 'completed') AND m.userid=u.id and c.id = %%COURSEID%%
UNION
SELECT
user2.firstname AS First,
user2.lastname AS Last,
'' AS Modulo,
'not_started' AS status,
TO_CHAR(TO_TIMESTAMP(st.value::int), 'DD/MM/YYYY HH24:MI') AS Inizio,
CAST(NULL AS text) AS Completamento
FROM prefix_user_enrolments AS ue
JOIN prefix_enrol AS e ON e.id = ue.enrolid
JOIN prefix_course AS c ON c.id = e.courseid
JOIN prefix_user AS user2 ON user2 .id = ue.userid
JOIN prefix_user_info_data AS uid ON uid.userid = user2.id
JOIN prefix_groups AS g ON g.courseid = c.id
JOIN prefix_groups_members AS m ON g.id = m.groupid
JOIN prefix_scorm AS sc ON sc.course=c.id
Left Join prefix_scorm_scoes_track AS st on st.scormid=sc.id AND st.userid=user2.id
WHERE st.element = 'x.start.time' AND m.userid=user2.id and c.id = %%COURSEID%%
ORDER BY Last, First
The output is this:
first last modulo status inizio completamento
name lastname module 1 completed 29/03/2021 16:57
name lastname module 1 not_started 29/03/2021 16:52
name lastname module 2 not_started 31/03/2021 11:37
name lastname module 2 completed 31/03/2021 11:41
name lastname module 3 not_started 31/03/2021 11:26
name lastname module 3 completed 31/03/2021 11:32
name lastname module 4 not_started 31/03/2021 11:52
name lastname module 4 completed 31/03/2021 12:10
So now my question is how can i combine the results to have "inizio" and "completamento" on the same row?

Related

Joining Data into a Single Column

I have this table in access
Userinfo
userid
Name
dept id
1
JJ
002
2
KK
001
Dept
deptid
Dept Name
001
Testing
002
Sorting
003
Designing
Checkinout
userid
Name
Checktime
Checktype
1
JJ
2/5/2022 7:45:10 AM
1
1
JJ
2/5/2022 18:00:10 PM
0
1
JJ
2/6/2022 6:30:00 AM
1
1
JJ
2/6/2022 18:10:30 PM
0
2
KK
2/6/2022 6:10:30 AM
1
2
KK
2/6/2022 18:20:30 PM
0
But i want to create a Inner join that will show this table
userid
Name
Deptname
In
Out
1
JJ
Sorting
2/5/2022 7:45:10 AM
2/5/2022 18:00:10 PM
1
JJ
Sorting
2/6/2022 6:30:00 AM
2/6/2022 18:10:30 PM
1
KK
Testing
2/6/2022 6:10:30 AM
2/6/2022 18:20:30 PM
This is the SQL that i used but i dont know how to put 0 as Out and 1 as In
SELECT Userinfo.userid as ID,UserInfo.Name as Name,Dept.DeptName as Dept , Checkinout.Checktime
from ( Userinfo
inner join Checkinout on Userinfo.userid = Checkinout.userid )
inner join Dept on Userinfo.DeptId =Dept.DeptId ;
Starting from the non-normalized Checkinout you can get everything but Out directly. Then add a calculated field to the query to look up the appropriate Out Checktime for each In Checktime:
Out: (SELECT TOP 1 q.Checktime FROM [Checkinout] as q WHERE (q.userid = [Checkinout].[userid]) AND (q.Checktype = 0) AND (q.Checktime > [Checkinout].[Checktime])
ORDER BY q.Checktime ASC)
SQL:SELECT Userinfo.userid, Userinfo.Username, Dept.[Dept Name], Checkinout.Checktime AS [In], (SELECT TOP 1 q.Checktime FROM [Checkinout] as q WHERE (q.userid = [Checkinout].[userid]) AND (q.Checktype = 0) AND (q.Checktime > [Checkinout].[Checktime])
ORDER BY q.Checktime ASC) AS Out
FROM (Dept INNER JOIN Userinfo ON Dept.deptid = Userinfo.[dept id]) INNER JOIN Checkinout ON Userinfo.userid = Checkinout.userid
WHERE (((Checkinout.Checktype)=1))
'I used a nested query for the calculated field and calculated Out with the business rules that each user check-in must have a corresponding and later check-out by the same user without any check-in/check-outs between.

SQL Query: Customer Table Contains Different type of EmpIDs and i want to get their name in a single row

I got a customer table and each customer has 4 different employeeID (tranieeID,RepresenterID,CoridatorID and ManagerID) I want to get all these employees name rather then their ID in single row.
CustomerTable
|CustomerID|CustomerName|tranieeID|RepresenterID |CoridatorID |ManagerID
------------------------------------------------------------------------
01 Mr T 100 101 102 103
EmployeeTable
EmpID | EmpName
---------------
100 Mr A
101 Mr B
102 Mr C
103 Mr D
What I need
CustomerID | CustomerName | tranieeName | RepresenterName | CoridatorName | ManagerName
----------------------------------------------------------------------------------------
01 Mr T Mr A Mr B Mr C Mr D
I did inner join but I got 4 Rows, is there any way to get all these with a single row?
Thank you for your help!
JOIN should work. I would recommend LEFT JOIN in case any of the values are not filled in:
select c.*,
et.empname as traineeName,
er.empname as RepresenterName,
ec.empname as CoridatorIDName,
em.empname as ManagerName
from customertable c left join
employeetable et
on c.traineeID = et.empid left join
employeetable er
on c.RepresenterID = et.empid left join
employeetable ec
on c.CoridatorID = ec.empid left join
employeetable em
on c.ManagerID = em.empid
You could use a correlated subquery in each instance, such as
select c.CustomerId, CustomerName,
(select Empname from EmployeeTable e where e.EmpID=c.TranieeId) TraineeName,
(select Empname from EmployeeTable e where e.EmpID=c.RepresenterId) RepresenterName,
... etc
from CustomerTable c

Query to get grandparents and grandkids

I got a table people:
ID name surname mother_id father_id
--------------------------------------------
1 John smith null null
2 kate m null null
3 philip smith 2 1
4 dimitr smith 7 3
etc.
I tried this query.
SELECT
p.name, P.surname,
c.name as 'Mothers name', c.surname as 'Mothers surname',
gm.name as 'Grandmother name', gm.surname as 'Grandmother surname'
FROM
dbo.people AS p
JOIN
dbo.people AS c ON (c.mother = p.Id)
JOIN
dbo.people AS gm ON (gm.mother = c.Id)
But it doesn't really return what I expected
Problem with ON clause :
select p.name, p.surname,
coalesce(pm.name, '') as mothername, coalesce(pm.surname, '') as mothersurname,
coalesce(pf.name, '') as grandmothername,
coalesce(pf.surname, '') as grandmothersurname
from people p left join
people pm
on pm.id = p.mother_id left join -- use mother_id from people p
people pf
on pf.id = p.father_id; -- use father_id from people p;
Here is db-fiddle.

SQL Database Table Joining to create an IdealTable

I need some helps to join the tables I have currently.
Leave, Overtime And Roster's Date, EmployeeID need to match
Note: ShiftDuration is set to default value = 8.25
Note: Leave and Overtime table will only have entries when an employee applies for leave and overtime.
Employee
EmplyeeeID | Username | Password | GivenName | FamilyName | TeamID | ContactNo | StaffType
------------------------------------------------------------------------------------------
123 123 abc John Snow 1 999 1
1234 1234 abcd Jack Waller 2 223 1
12345 12345 abcde Ali Saw 1 123 1
123456 123456 abcdef Peter Peter 2 223 1
1234567 1234567 abcdeg Bryan Peter 1 333 1
Roster
Duty_ID | EmployeeID | Date | ShiftType | ShiftDuration
--------------------------------------------------------------------
2 123 2018-05-05 1 8.25
4 1234 2018-05-04 1 8.25
5 12345 2018-05-05 1 8.25
7 123456 2018-05-04 1 8.25
8 1234567 2018-05-05 1 8.25
Overtime
OTID | EmployeeID | Date | OT_Duration | OT_Reason
------------------------------------------------------------
2 1234 2018-05-04 2 Cover Duty
Leave
LeaveID | EmployeeID | Date | Duration_Off | Reason
----------------------------------------------------------
3 123 2018-05-05 2 NIL
IdealTable (Via Query)
Date | EmployeeID | GivenName | FamilyName | TeamID | ShiftType | ShiftDuration | Duration_Off | OT_Duration | Total_Hours
---------------------------------------------------------------------------------------------------------------------------------
2018-05-05 123 John Snow 1 1 8.25 2 0 6.25
2018-05-04 1234 Jack Waller 1 1 8.25 0 2 10.25
2018-05-05 12345 Ali Saw 1 1 8.25 0 0 8.25
2018-05-04 123456 Peter Peter 1 1 8.25 0 0 8.25
2018-05-05 1234567 Bryan Peter 1 1 8.25 2 0 8.25
I have 4 tables, they are Employee, Leave, Overtime, Roster
Employee
-EmployeeID (PK)
-Username
-Password
-GivenName
-FamilyName
-TeamID
-ContactNo
-StaffType
Leave
-LeaveID (PK)
-EmployeeID (FK)
-Date
-Duration_Off
-Reason
Overtime
-OTID (PK)
-EmployeeID (FK)
-Date
-OT_Duation
-OT_Reason
Roster
-DutyID (PK)
-EmployeeID (FK)
-Date
-ShiftType
-Shift Duration (Default Value = 8.25)
What I am trying to do is join the data from this 4 tables using Query
Ideal Table
-Date (From Leave, Overtime and Roster Table)
-EmployeeID (Employee Table)
-GivenName (Employee Table)
-FamilyName (Employee Table)
-TeamID (Employee Table)
-ShiftType (Roster Table)
-ShiftDuration (Roster Table)
-Duration_Off (Leave Table)
-OT_Duration (Overtime Table)
-Total_Hours (Calculation from joint table [(ShiftDuration + OT_Duration) - Duration_Off]
My database diagram design Do ignore the TimeData table as I initially wanted to use the TimeData table to achieve the IdealTable
My current query
USE [SMRT Dashboard]
GO
;With Dates
AS
(
SELECT [Date] FROM dbo.Roster
UNION
SELECT [Date] FROM dbo.Leave
UNION
SELECT [Date] FROM dbo.Overtime
),
Work_Matrix
AS
(
SELECT EmployeeID,[Date],ShiftType,ShiftDuration,CAST(NULL AS Decimal(30,2)) AS Duration_Off,CAST(NULL AS Decimal(30,2)) AS OT_Duration
FROM dbo.Roster
UNION ALL
SELECT EmployeeID,[Date], NULL, NULL,Duration_Off
FROM dbo.Leave
UNION ALL
SELECT EmployeeID,[Date],NULL,NULL,NULL,OT_Duration
FROM dbo.Overtime
)
SELECT d.[Date],
e.EmployeeID,
e.GivenName,
e.FamilyName,
e.TeamID,
w.ShiftType,
w.ShiftDuration,
w.Duration_Off,
w.OT_Duration,
w.Total_Hours
FROM Dates d
INNER JOIN
(
SELECT EmployeeID,
[Date],
MAX(ShiftType) AS ShiftType,
SUM(ShiftDuration) AS ShiftDuration,
SUM(Duration_Off) AS Duration_Off,
SUM(OT_Duration) AS OT_Duration,
SUM(ShiftDuration) + SUM(OT_Duration) - SUM(Duration_Off) AS Total_Hours
FROM Work_Matrix
GROUP BY EmployeeID,
[Date]
)w
ON d.[Date] = w.[Date]
JOIN dbo.Employee e
ON e.EmployeeID = w.EmployeeID
Current Errors:
Msg 205, Level 16, State 1, Line 4
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
I have not tested this but you may now check this. Hope your problem will be solved.
SELECT
a.EmployeeID,
a.GivenName,
a.FamilyName,
a.TeamID,
d.ShiftType,
d.ShiftDuration,
b.Duration_Off,
c.OT_Duration,
b.Date,
(d.ShiftDuration + c.OT_Duration) - b.Duration_Off as Total_Hours
FROM Employee a
INNER JOIN Roster d ON a.EmployeeID = d.EmployeeID
LEFT JOIN Leave b ON a.EmployeeID = b.EmployeeID
LEFT JOIN Overtime c ON a.EmployeeID = c.EmployeeID
I assume Date is same from all three tables (Leave, Overtime and Roster Table)
Try this query :
select
l.Date,
o.Date,
r.Date,
e.EmployeeID,
e.GivenName,
e.FamilyName,
e.TeamID,
r.ShiftType,
r.ShiftDuration,
l.Duration_Off,
o.OT_Duration,
((r.ShiftDuration+o.OT_Duration)-l.Duration_Off) as Total_Hours
FROM Employee e
INNER JOIN Leave l ON e.EmployeeID = l.EmployeeID
INNER JOIN Overtime o ON e.EmployeeID = o.EmployeeID
INNER JOIN Roster r ON r.EmployeeID = r.EmployeeID;
Try this Query ! You will get the correct output .
SELECT
e.EmployeeID AS 'Emp ID',
e.GivenName AS 'Emp Name',
l.Date AS Date,
e.FamilyName AS 'Family Name',
e.TeamID AS 'Team ID',
r.ShiftType AS 'Shift Type',
r.ShiftDuration AS 'Shift Duration',
l.Duration_Off AS 'Duration Off',
o.OT_Duration AS 'OT Duration',
(r.ShiftDuration + o.OT_Duration) - l.Duration_Off as 'Total Hours'
FROM
Employee e,
Leave l,
Overtime o,
Roster r
WHERE
e.EmployeeID = l.EmployeeID
AND
e.EmployeeID = o.EmployeeID
AND
e.EmployeeID = r.EmployeeID
I think the issue here is that an employee may have leave, may have overtime, or neither. By using INNER JOIN, you're filtering down the set of employees to ones that have Leave, and on a Roster, and have Overtime.
I created a SqlFiddle with the data you present (see here) that should get you closer.
SELECT
COALESCE(r.Date, o.Date, l.Date) as Date,
e.EmployeeID,
e.GivenName,
e.FamilyName,
e.TeamID,
r.ShiftType,
r.ShiftDuration,
IFNULL(l.Duration_Off, 0) as Duration_Off,
IFNULL(o.OT_Duration, 0) as OT_Duration,
r.ShiftDuration + IFNULL(o.OT_Duration, 0) - IFNULL(l.Duration_Off, 0) as Total_Hours
FROM Employee e
INNER JOIN Roster r on
e.EmployeeID = r.EmployeeID
LEFT JOIN Overtime o on
e.EmployeeID = o.EmployeeID
LEFT JOIN `Leave` l on
e.EmployeeID = l.EmployeeID
There's a few cavaets that this query won't solve:
If an employee has multiple leave entries or multiple overtime entries, the person will be listed N times. You can potentially use a GROUP BY statement to deal with this
The sample data in your question doesn't reconcile correctly. For example, Employe 1234 has a shift on 5/4/2018 and OT on 5/5/2018 but gets 10.25 on 5/4/2018.
If you use TimeData, this becomes a lot easier (assuming one record per date per employee):
SELECT
COALESCE(r.Date, o.Date, l.Date) as Date,
e.EmployeeID,
e.GivenName,
e.FamilyName,
e.TeamID,
r.ShiftType,
IFNULL(r.ShiftDuration, 0) as ShiftDuration,
IFNULL(l.Duration_Off, 0) as Duration_Off,
IFNULL(o.OT_Duration, 0) as OT_Duration,
IFNULL(r.ShiftDuration, 0) + IFNULL(o.OT_Duration, 0) - IFNULL(l.Duration_Off, 0) as Total_Hours
from TimeData t
INNER JOIN Employee e on
t.EmployeeID = e.EmployeeID
LEFT JOIN Roster r on
t.Duty_ID = r.Duty_ID
LEFT JOIN Overtime o on
t.OTID = o.OTID
LEFT JOIN `Leave` l on
t.LeaveID = l.LeaveID
Example SqlFiddle can be found here

SQL inner joins on three tables

I have three tables that needs to be checked in order to find out on which courses professor is active.
table_teacher
table_course; and
table_teacher_holds_course
table_teacher looks like this:
username | title
---------+----------
john | professor
mark | assistant
table_course looks like this:
course_code | course_name | semester | school_year
-------------+-------------+----------+------------
course_code1| course1 |semester1 | 2015
course_code2| course2 |semester2 | 2015
course_code3| course3 |semester3 | 2015
table_teacher_holds_course looks like this:
username | course_code
---------+-------------
john |course_code1
mark |course_code2
and when I have professors username when he logs on the page, I would like to do left inner join on these three tables in order to show professors courses from table_course
Can someone help me with this, because it is first time to me to use sql to join search in several tables.
Join on the tables common fields
SELECT *
FROM table_teacher t
INNER JOIN table_teacher_holds_course hc ON t.username = hc.username
INNER JOIN table_course c ON hc.course_code = c.course_code
Relevant example:
SELECT t.title, t.username, c.course_code, c.course_name, c.semester, c.school_year
FROM table_teacher t
INNER JOIN table_teacher_holds_course hc ON t.username = hc.username
INNER JOIN table_course c ON hc.course_code = c.course_code
WHERE t.username = 'John'
Result:
title username course_code course_name semester school_year
professor John course_code1 course1 semester1 2015