Oracle Fetching the Result from two Different conditions - sql

I need to get the Values from tables with different conditions for a particular field. For Particular domain id (domain_id) there must be number of usernames assigned different system_id.
For specific system id (123) a column domain (domain_id ) should have the active username only starts with 'a-' 0r 'A-' and all other username should be disabled except the username starts with 'a-' 0r 'A-'.
Please help to get the Expected result ;
The Query I used as below:
SELECT e.domain_id, e.first_name, e.last_name, e.type, e.username,e.system_name
FROM (SELECT p.domain_id, p.first_name,p.last_name,p.type, u.username, u.status, u.system_id ,s.system_name
FROM ur_username u JOIN ur_username_person up ON u.username_id = up.username_id JOIN ur_person p ON up.person_id = p.person_id
JOIN ur_system s ON u.system_id = s.system_id
WHERE u.username LIKE 'A-%' OR username LIKE 'a-%'
AND u.status = 'ACTIVE'
AND u.system_id = 349 ) E
WHERE e.domain_id IN ( SELECT p.domain_id
FROM ur_username u
JOIN ur_username_person up ON u.username_id = up.username_id
JOIN ur_person p ON up.person_id = p.person_id
WHERE u.status = 'DISABLED'
AND u.system_id = 349 )

Related

How do I display matching rows for multiple users in Postgres?

I'm new to Postgres and I'm looking to retrieve a list of courses that a particular set of users are enrolled in as course leaders in the same course(s). Hopefully I've explained that clearly.
It's returning a list of all the courses that that all the users are enrolled in as course leader rather than a list of the same courses that they are enrolled in as course leader.
This is my original query
select distinct(cm.course_id), cm.course_name, cm.dtcreated, cm.dtmodified
from course_main cm
inner join course_users cu on cm.pk1 = cu.crsmain_pk1
inner join users u on u.pk1 = cu.users_pk1
where u.user_id IN ('msassar5','mfztsjc3', 'mzysshba', 'mftssag3', 'mfztslmi', 'mfztsml7', 'mtlsscm5', 'msdsshp2', 'mzysscp9', 'mcyssmy')
and role = 'P' - 'P' denotes course leader
and cm.service_level = 'F' -- 'F' denotes full course
order by cm.course_id, cm.dtcreated asc
I need to compare all the courses that each of the users are enrolled in as course leader (P) and only display the courses that are in each list, but I'm not sure the best approach.
I've read about the INTERSECT statement and using that does produce the result I expect, but that seems to be an inelegant solution as I would have to add another query to the INTERSECT list for each additional user.
Here is me INTERSECT query
select distinct(cm.course_id), cm.course_name, cm.dtcreated, cm.dtmodified
from course_main cm
inner join course_users cu on cm.pk1 = cu.crsmain_pk1
left outer join users u on u.pk1 = cu.users_pk1
where u.user_id = '<USERNAME>'
and role = 'P'
and cm.service_level = 'F'
intersect
select distinct(cm.course_id), cm.course_name, cm.dtcreated, cm.dtmodified
from course_main cm
inner join course_users cu on cm.pk1 = cu.crsmain_pk1
left outer join users u on u.pk1 = cu.users_pk1
where u.user_id = '<USERNAME>'
and role = 'P'
and cm.service_level = 'F'
intersect
...
...
...
Here is my result, which is correct. This is the only course that ALL the users in my query are enrolled in
cm.course_id -> "I3016-BMAN-62082-1201-2SE-005000"
cm.course_name -> "BMAN62082 The Management of International Organizational Change 2020-21 2nd Semester"
Date Created -> 2020-08-24 11:30:22.064
Date Modified -> 2020-08-24 11:32:45.978
Is there a more elegant solution?
Any help will be appreciated.
thanks
If you want an intersection -- that is courses where all 10 users are leaders -- then use aggregation and a having clause:
select cm.course_id, cm.course_name, cm.dtcreated, cm.dtmodified
from course_main cm join
course_users cu
on cm.pk1 = cu.crsmain_pk1 join
users u
on u.pk1 = cu.users_pk1
where u.user_id in ('msassar5', 'mfztsjc3', 'mzysshba', 'mftssag3', 'mfztslmi', 'mfztsml7', 'mtlsscm5', 'msdsshp2', 'mzysscp9', 'mcyssmy') and
role = 'P' and
cm.service_level = 'F' -- 'F' denotes full course
group by cm.course_id
having count(*) = 10;

Get all data for an entity from another table in one query

I have this query
select *
from (
select c.*,p.name as project_name,u.firstname || ' ' || u.lastname as fullname, u.email as owner_email, u.payment_method, u as user, u.id as user_id, u.api_id, u.api_key,
v.name as vendor_name, v.exid as vendor_id, s.number as sim_number, vm.exid as vendor_model_id, vm.name as vendor_model_name, cr.status as is_recording,
cr.storage_duration as cloud_recording_storage_duration, cr.schedule as schedule, cr.frequency as frequency,
(select count(id) as total from camera_shares cs where c.id=cs.camera_id) as total_share
from cameras c
inner JOIN users u on c.owner_id = u.id
left JOIN projects p on c.project_id = p.id
left JOIN sims s on c.id = s.camera_id
left JOIN vendor_models vm on c.model_id = vm.id
left JOIN vendors v on vm.vendor_id = v.id
left JOIN cloud_recordings cr on c.id = cr.camera_id
) c
this gives me all cameras and with all relevant values which I require.
now there is another table, snapshot_extractors and it has a relation with the camera on id and camera_id in extractors table, as one camera can have more than 1 extractors.
In the above query, I want to get all extraction for one camera, I can do it in a separate query, but is it possible to get all extractions in the above query as an array of all extractions for a camera?
You can use another correlated subquery:
(select array_agg(e.extraction)
from snapshot_extractors e
where e.camera_id = c.camera_id
)

INSERT INTO not working with my select

I need to copy some data from one table to another:
There is a table that has the correct date (AUDITLOG), column TIME but I need to put it in the USER table, column USERS_DATE and associate with the correct user...
The SELECT returns the correct data by itself, I'm having issue using the SELECT INTO statement. My hacked up code below:
INSERT INTO users (USERS_DATE) WHERE USERID=U.USERID
(SELECT U.USERID,
javaTimeStampToDate (L.TIME)
AS "Last Login"
FROM COMPANY C,
USERS U,
AUDITMAP M,
AUDITLOG L
WHERE C.COMPANYID = U.COMPANYID
AND U.USERID = M.ROWID
AND M.AUDITID = L.AUDITID
AND C.APPLICATION = 'A'
AND L.NOTES LIKE '%went inactive%'
AND U.STATUS = 0);
Try with the below query for sql server.
I think you need an update query. Also change your commas with JOIN condition.
UPDATE U
SET U.USERS_DATE=L.TIME
FROM COMPANY C
JOIN USERS U ON C.COMPANYID = U.COMPANYID
JOIN AUDITMAP M ON U.USERID = M.ROWID
JOIN AUDITLOG L ON M.AUDITID = L.AUDITID
WHERE C.APPLICATION = 'A'
AND L.NOTES LIKE '%went inactive%'
AND U.STATUS = 0
use below query for oracle,
MERGE INTO USERS U
USING
(
SELECT M.ROWID,L.Time
FROM AUDITMAP M
JOIN AUDITLOG L ON M.AUDITID = L.AUDITID
WHERE L.NOTES LIKE '%went inactive%'
) Au ON (U.USERID = Au.ROWID)
WHEN MATCHED THEN UPDATE
SET U.USERS_DATE = Au.TIME
WHERE U.STATUS = 0 AND EXISTS (select 1
from COMPANY c
where .COMPANYID = U.COMPANYID AND C.APPLICATION = 'A')

sql : query same column multiple times AS different columns, with multiple values returned 1 per row

I need to build a report that is structured as follows:
Name, Field_1, Field_2, Field_3
Jim, opt_1, y, 12
Jane, opt_2, n, 64
etcetera
I'm pulling from Moodle database tables, structure shown in following images. mdl_user_info_data, mdl_user_info_field, mdl_user has same columns as others, all I'm getting from it is name so I'm not bothering to include it here. That part works fine.
Here's the best I could come up with so far, so you can see how the tables join:
SELECT
CONCAT (u.firstname, u.lastname) Name,
(SELECT d.data FROM mdl_user_info_data d JOIN mdl_user_info_field f ON f.id = d.fieldid WHERE f.shortname = "Field_1" GROUP BY d.userid),
(SELECT d.data FROM mdl_user_info_data d JOIN mdl_user_info_field f ON f.id = d.fieldid WHERE f.shortname = "Field_2" GROUP BY d.userid),
(SELECT d.data FROM mdl_user_info_data d JOIN mdl_user_info_field f ON f.id = d.fieldid WHERE f.shortname = "Field_3" GROUP BY d.userid),
FROM mdl_user u
JOIN mdl_user_info_data d ON d.userid = u.id
JOIN mdl_user_info_field f ON d.fieldid = f.id
GROUP BY d.userid
ORDER BY `Name` ASC
I know I'm barking up the wrong tree with my sub-queries, but not sure what to do in place of the GROUP BYs. My current query will return all values of each given Field_x for in each row, when I need to return only the value that corresponds to the user named in column 1.
Any help much appreciated.
I'm not positive about moodle or it's sql syntax, but if common, you might get what you want by doing left-joins to the table multiple times, each with its criteria qualification, then just use the different ALIAS references to get your pieces...
SELECT
CONCAT (u.firstname, u.lastname) Name,
dFld1.Data as Field1Data,
dFld2.Data as Field2Data,
dFld3.Data as Field3Data
FROM
mdl_user u
LEFT JOIN mdl_user_info_data dFld1
ON u.id = dFld1.userid
LEFT JOIN mdl_user_info_field fFld1
ON dFld1.fieldid = fFld1.id
AND fFld1.shortname = "Field_1"
LEFT JOIN mdl_user_info_data dFld2
ON u.id = dFld2.userid
LEFT JOIN mdl_user_info_field fFld2
ON dFld2.fieldid = fFld2.id
AND fFld2.shortname = "Field_2"
LEFT JOIN mdl_user_info_data dFld3
ON u.id = dFld3.userid
LEFT JOIN mdl_user_info_field fFld3
ON dFld3.fieldid = fFld3.id
AND fFld3.shortname = "Field_3"
ORDER BY
`Name` ASC
I have this query with LEFT-JOINs if any such links may NOT have a value.
As for the group by, this would only be required if there are multiple entries for one or more of the underlying tables for a given user and field 1, 2 or 3 entries respectively.
An alternative solution.
SELECT u.id, u.firstname, u.lastname, f.fieldname1, f.fieldname2
FROM mdl_user u
JOIN (
SELECT d.userid,
MAX(CASE WHEN f.shortname = 'fieldname1' THEN d.data ELSE null END) AS fieldname1,
MAX(CASE WHEN f.shortname = 'fieldname2' THEN d.data ELSE null END) AS fieldname2
FROM mdl_user_info_field f
JOIN mdl_user_info_data d ON d.fieldid = f.id
WHERE f.shortname IN ('fieldname1', 'fieldname2')
GROUP BY d.userid) f ON f.userid = u.id
Concat will work for MySql, but you should use database compatible functions - https://docs.moodle.org/dev/Data_manipulation_API#SQL_compatibility_functions
So use the result of
$DB->sql_concat('u.firstname', 'u.lastname');

How to place an ORDER BY clause in SQL between UNIONS

I want to implement simple SQL query that will return a sorted list. The problem is that I get syntax errors for placing the ORDER BY clause anywhere I put it.
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
users u
JOIN
UserRoles ur ON ur.UserID = u.UserID
JOIN
Roles_FunctionRoles rfr ON rfr.RoleID = ur.RoleID
JOIN
FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
u.UserName = #UserName
AND u.Active = 1
UNION
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
Roles r
JOIN
Roles_FunctionRoles rfr ON rfr.RoleID = r.RoleID
JOIN
FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
r.RoleName = 'Authenticated Users'
AND #UserName IS NOT NULL
AND LEN(#UserName) > 0
What I want to insert:
ORDER BY fr.DisplayName ASC
EDIT
If I create a subquery using
SELECT *
FROM
(
[my initial query]
)
ORDER BY
[COLUMN NAME] ASC
I get the following error message:
Incorrect syntax near 'ORDER'. Expected 'AS', 'ID' or 'QUOTED_id'
In most databases, you can only place an order by at the end of a union.
Because the union abstracts away individual table aliases, you only have to list the column name. So omit the fr. :
ORDER BY DisplayName
The ORDER BY clause needs to be placed after the last SELECT statement of the Union.
select * from(
*what you have there*
) as foo
order by DisplayName ASC
I'm not in front of an IDE so the syntax may be off a bit but that's the idea.
e: yeah, figured I'd jack up the syntax...alias added :)
Your not selecting DisplayName so you cannot use it to ORDER BY a set derived from a UNION. If you want to order by it and omit it from the results;
;WITH T (FunctionRoleID, FunctionRoleInternalName, DisplayName) AS (
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName, fr.DisplayName
FROM users u
JOIN UserRoles ur ON ur.UserID = u.UserID
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = ur.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
u.UserName = #UserName
AND
u.Active = 1
UNION
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName, fr.DisplayName
FROM
Roles r
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = r.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
r.RoleName = 'Authenticated Users'
and #UserName is not null and LEN(#UserName) > 0
)
SELECT
FunctionRoleID, FunctionRoleInternalName
FROM T
ORDER BY DisplayName
Try
SELECT * FROM (
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
users u
JOIN UserRoles ur ON ur.UserID = u.UserID
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = ur.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
u.UserName = #UserName
AND
u.Active = 1
UNION
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
Roles r
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = r.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
r.RoleName = 'Authenticated Users'
and #UserName is not null and LEN(#UserName) > 0 ) a
ORDER BY a.FunctionRoleInternalName ASC
Basically, you are selecting against the result of the UNION and then performing the ORDER BY...note that I use "FunctionRoleInternalName"...you can change that to "DiaplayName" only of you use that as a column ALIAS in the UNION queries...e.g. "FunctionRoleInternalName AS DisplayName"
For UNION, ORDER BY goes at the end and applies to the combined result of both queries; you can't order by a column that is not selected by both queries in the union.
what you need to do is select fr.DisplayName in both queries; then you can order by it.
If you don't want the display name to be one of the output columns, nest the whole thing in an outer query that retrieves just the columns you want.