I have one table and I need to check if two users, for whom I have the IDs (e.g. 20 and 21) share the same course, just true or false.
Table: jos_gj_users
Columns: id_user, id_group
Data Example: (20; 4)
(20; 5)
(20; 6)
(21; 6)
(21; 7)
The data above shows that user 20 and user 21 share the course 6 but how do I get this with SQL just by entering the IDs and without looping through the results with PHP?
Try a self-join:
SELECT T1.id_group
FROM jos_gj_users T1
JOIN jos_gj_users T2
ON T1.id_group = T2.id_group
WHERE T1.id_user = 20
AND T2.id_user = 21
To just get a "true or false" result you can check from the client to see if at least one row exists in the result set rather than fetching the entire results.
Alternatively you can do it in SQL by wrapping the above query in another SELECT that uses EXISTS:
SELECT CASE WHEN EXISTS
(
SELECT T1.id_group
FROM jos_gj_users T1
JOIN jos_gj_users T2
ON T1.id_group = T2.id_group
WHERE T1.id_user = 20
AND T2.id_user = 21
) THEN 1 ELSE 0 END AS result
This query returns either 0 (false) or 1 (true).
The idea is that you have to join the table to itself. In the first half you look for user 1 and in the second half you look for user 2. And of course only those rows that have the same id_group in both half are relevant:
SELECT count(*)
FROM jos_gj_users As j1, jos_gj_users As j2
WHERE j1.id_user = 20 AND j2.id_user = 21
AND j1.id_group = j2.id_group
This will always return one row with one column: The number of shared courses. If it is 0, they don't share any courses.
You could do it with a subselect:
select id_group
from jos_gj_users
where (id_user = 20)
and id_group in (select id_group from jos_gj_users where id_user = 21)
SELECT COUNT(*) > 0 FROM jos_gj_users WHERE id_user=54321 AND id_group IN ( SELECT id_group FROM jos_gj_users WHERE id_user = 1345 )
This is query that shows users from same groups.
SELECT
*
FROM
jos_gj_users T1
INNER JOIN jos_gj_users T2 ON T1.id_group = T2.id_group
Give this a try - it accepts the input parameters in the first bolded area, and returns a value of TRUE or FALSE via a CASE statement based on the values in the second bolded areas.
SELECT DISTINCT CASE WHEN
(SELECT DISTINCT COUNT(id_group) FROM jos_gj_users WHERE id_user IN (20, 21) GROUP BY id_group
HAVING COUNT(DISTINCT id_user) = 2) IS NOT NULL THEN 'TRUE'
ELSE 'FALSE'
END
FROM jos_gj_users
Related
I am trying to use a case when to enforce some data access security that's not standard.
The basics of what I am trying to do keep causing the "more than one row" error.
I want to use 2 different subqueries with the result of the case when determining which list will be returned.
Example logic
SELECT CASE
WHEN condition 1 is true THEN (SUBQUERY 1)
WHEN condition 2 is true THEN (SUBQUERY 2)
END AS ACCESS
FROM DUAL
Both subqueries on there own work fine and fetch back correct values, put them into the brackets above and it fails.
SUBQUERY 1
SELECT DISTINCT FND.PK1_START_VALUE
FROM FND_GRANTS FG
JOIN FND_OBJECTS_VL FO
ON FO.OBJECT_ID = FG.OBJECT_ID
JOIN FND_FORM_FUNCTIONS_VL FFF
ON FO.OBJECT_ID = FFF.OBJECT_ID
JOIN FND_MENU_ENTRIES FME
ON FME.MENU_ID = FG.MENU_ID AND FFF.FUNCTION_ID = FME.FUNCTION_ID
LEFT JOIN FND_OBJECT_INSTANCE_SETS_VL FOIS
ON FG.INSTANCE_SET_ID = FOIS.INSTANCE_SET_ID
JOIN FND_SESSION_ROLES FSR
ON FG.ROLE_NAME = FSR.ROLE_NAME
JOIN FND_SESSIONS FS
ON FS.SESSION_ID = FSR.SESSION_ID
LEFT JOIN FND_FLEX_VALUES_VL FLV
ON FLV.DESCRIPTION = SUBSTR(FG.NAME, 1, CASE WHEN INSTR(FG.NAME,'Area')< 1 THEN INSTR(FG.NAME,'Cost')-2)
ELSE (INSTR(FG.NAME,'Area')-2)
END)
JOIN FND_TREE_NODE FND
ON FLV.FLEX_VALUE = FND.PARENT_PK1_VALUE
WHERE FG.ROLE_NAME IN (:P_ROLE)----:P_ROLE is a list of VALUES fetching back the users system access.
AND FND.TREE_STRUCTURE_CODE = 'GL_ACCT_FLEX'
AND FND.TREE_CODE ='Cost Centre-T'
AND FND.DEPTH ='4'
ORDER BY FND.PK1_START_VALUE ASC)
SUBQUERY 2----idea here is the user has none of the roles in P_ROLE and therefore has all access to all sections
SELECT DISTINCT FND.PK1_START_VALUE
FROM FND_TREE_NODE FND
WHERE FND.TREE_STRUCTURE_CODE IN('GL_ACCT_FLEX')
AND FND.TREE_CODE IN('Cost Centre-T')
AND FND.DEPTH IN('4')
NOTE some sensitive data has been redacted from the query and replaced
One (simple) option is to UNION them:
select columns
from subquery_1
where condition = 1
union all
select columns
from subquery_2
where condition = 2
Hmmm . . . I think you want union all:
SELECT q1.*
FROM (SUBQUERY 1) q1
WHERE condition1
UNION ALL
SELECT q2.*
FROM (SUBQUERY 2) q1
WHERE (NOT condition 1) AND -- may not be necessary
(condition 2) is true ;
Note: This assumes that the column(s) returned by each subquery are compatible -- in both number and types. The name in the result set is taken from the first subquery.
You can do something like the below using CASE
WITH sub1
AS (SELECT ROWNUM rw,
data
FROM sub_query1),
sub2
AS (SELECT ROWNUM rw,
data
FROM sub_query2)
SELECT CASE
WHEN condition1 = 1 THEN a1.data
WHEN condition1 = 2 THEN b1.data
ELSE NULL
END case1
FROM sub1 a1
full outer join sub2 b1
ON a1.rw = b1.rw
I have two tables named [DrugPrescriptionEdition] and [PrescriptionDoseDetail] and now, I join that two tables using the below query and taking a result set.
select * from DrugPrescription dp where id in(
SELECT distinct dpe.template
FROM [DrugPrescriptionEdition] dpe
join PrescriptionDoseDetail pdd on pdd.prescription = dpe.id
where doseEnd_endDate is NULL and doseEnd_doseEndType =1
)
but now I want to take records only contain, (1,2) combination of 'datasource' column and prescription.id should be same.
Example : like records { prescriptionID =4 and there contain ,(1,2) }. I will not consider, only 1 ,or 2 contain records.
Need some expert help to adding this conditions to my above query and modify it .
Expected result : I need to filter out , above query result using this, new condition too.
Let me assume your records are in a single table. Here is one method:
select t.*
from t
where (t.dataSource = 1 and
exists (select 1
from t t2
where t2. prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
) or
(t.dataSource = 2 and
exists (select 1
from t t2
where t2.prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
);
It is unclear if any other data sources are allowed. If they are not, then add:
and
not exists (select 1
from t t3
where t3.prescriptionid = t.prescriptionid and
t3.dataSource not in (1, 2)
)
Tables in my db:
CREATE TABLE items (
id serial NOT NULL,
user_id integer NOT NULL,
status smallint
);
CREATE TABLE phones (
phone character varying,
users integer[]
);
My Query for find phone numbers where status = 1:
SELECT phones.phone, COUNT(*) AS "count"
FROM phones,items
WHERE phones.phone = ANY (Array['7924445544', '8985545444'])
AND items.user_id = ALL (phones.users) AND items.status = 1
GROUP BY phones.phone;
Query out:
phone | count
------------+------
7924445588 | 3
Need out with ZERO count:
phone | count
------------+-------
8985545444 | 0
7924445544 | 3
How to get that?
It's a bit tricky to create non-existing rows. (There are billions of them, at least...)
Do a UNION ALL with a select providing the result you want if that phone no doesn't exist.
<current query>
UNION ALL
select '8985545444',0
from one_row_table where not exists (select 1 from phones
where phones.phone = '8985545444')
EDIT:
If the phone numbers do exists, but not fulfill the WHERE clause conditions, use a correlated sub-select to do the count:
SELECT phones.phone,
(select count(*) from items
where items.status = 1
and items.user_id = phones.users) as "Count"
FROM phones
WHERE phones.phone = ANY (Array['7924445544', '8985545444'])
You shouldn't do that in the query. However it is rather easy to do it if you want to:
WITH phone_seek AS(
SELECT '8985545444' AS phone
UNION ALL
SELECT '7924445588 '
)
SELECT phone_seek.phone, COUNT(items.id) AS "count"
FROM
phones_seek
JOIN phones
ON phones_seek.phone = phones.phones
CROSS JOIN items
WHERE
items.user_id = ALL (phones.users) AND items.status = 1
GROUP BY phones.phone;
Count is an aggregate function and generally db engines produces count 0 when no row matches the criteria.
The reason why your query produces no results is inclusion of your phones.phone field in db and the group by.
1) A cheap solution to this is select only count(*) as your application
already be knowing the phone number:
SELECT COUNT(*) AS "count"
FROM phones, items
WHERE phones.phone = '8985545444'
AND items.user_id = ALL (phones.users) AND items.status = 1 ;
2) An ideal solution to this would be your application to handle 0 result
returned by db.
3) And if you need db to do all job you may use something like:
SELECT phones.phone, COUNT(*) AS "count"
FROM phones, items
WHERE phones.phone = '8985545444'
AND items.user_id = ALL (phones.users) AND items.status = 1
GROUP BY phones.phone;
UNION ALL
select '8985545444',0
from one_row_table where not exists (select 1 from phones
where phones.phone = '8985545444')
I'm not well versed with PostreSQL's array syntax, but this seems to be a simple outer join:
SELECT phones.phone, COUNT(items.user_id) AS "count"
FROM phones LEFT JOIN items
ON items.user_id = ALL (phones.users)
AND items.status = 1
WHERE phones.phone = ANY (Array['7924445544', '8985545444'])
GROUP BY phones.phone;
We can have users with multiple valueIDs. In SQL Server I am trying to pull all users that have valueID of 3 but do not have valueID of 1 and 2. So Table A would have a user column and a valueID column.
How do I write a SQL query to do this?
Also, any good resources to get my SQL query skills up to par?
Much appreciated.
Try:
SELECT user
FROM A outer
WHERE valueID = 3
AND NOT EXISTS
(
SELECT 1
FROM A inner
WHERE
(
valueID = 1
OR valueID = 2
)
AND inner.user = outer.user
)
Here's one more.... (all users with valueid = 3 and nothing else)
SELECT [USER]
FROM A
GROUP BY [USER]
HAVING MAX(CASE WHEN valueid = 3 THEN 0 when valueid IN (1,2) THEN 1 END) = 0;
This query will return all users that have values (3 and 1) or (3 and 2) or just 3
select user
from mytable t1
where valueId = 3
and (select count(distinct valueId)
from mytable t2 where t2.user = t1.user
and valueId IN (1,2)) < 2
A simple way to get what you asked if you meant users with a value of 3 except those which also have values of 1 and 2
Select s.UserID From SomeTable s
Where s.UserID NOT In
(select s1s.UserID From SomeTable s1s
inner join SomeTable s2s On s1s.UserID = s2s.UserID
Where s1s.ValueId = 1 And s2s.ValueId = 2)
Or
Select s.UserID From SomeTable s
Left Join
(select s1s.UserID From SomeTable s1s
inner join SomeTable s2s On s1s.UserID = s2s.UserID
Where s1s.ValueId = 1 And s2s.ValueId = 2) both
Where both.userID is null
I'm not really sure what your table structure is, but it's likely the below query should work depending on column names...
SELECT user, valueID
FROM users
WHERE valueID = 3
Please consider this Query:
SELECT tesd.State_Code,
tesd.City_Code,
tesd.Row_ID,
tesd.Qsno,
tesd.Total_Period,
tesd.Current_Period,
tesd.Week,
tesd.Block_No,
tesd.Family_ID,
tesd.Line_ID,
tesd.Page_ID
INTO #tmp
FROM Specification_Master tesm
INNER JOIN Specification_Details tesd
ON tesd.Master_Id = tesm.Id
WHERE tesm.[Year] = 2000
AND tesm.[Month] = 10
AND tesd.City_Code IN ('001')
I queried some data from 2 tables and insert them in #tmp .then I want to select data from 2 other tables and check one of that tables has values in #tmp tbale:
SELECT *
FROM tbl_Details D
INNER JOIN tbl_Master tem
ON D.ID_Master = tem.Id
WHERE D.Period <= 5
AND EXISTS (
SELECT Row_ID
FROM #tmp tm
WHERE tm.Current_Period > 1
AND tm.State_Code = tem.State_Code
AND tm.City_Code = tem.City_Code
AND tm.Qsno = tem.Qsno
)
AND D.[Status] > 2
when I run this query I got just one row but when I change EXISTS to NOT EXISTS I got more rows.I run this query seperatly :
SELECT Row_ID
FROM #tmp tm,tbl_Master tem
WHERE tm.Current_Period > 1
AND tm.Ostan_Code = tem.State_Code
AND tm.City_Code = tem.City_Code
AND tm.Porseshname_ID = tem.Qsno
and it returns 30 rows. Why Exists has this such behaivior ?
Exists returns a Boolean value based on the results of the subquery. It matters not if there are 1 or 30 rows returned. The number of rows you are retrieving is based on the select * statement, not the Exists clause.