Applying SQL WHERE Conditionally - sql

TABLE A
-------
USER ACCESS RECORD_IDN
1 ALL NULL
2 PARTIAL 1
2 PARTIAL 2
3 PARTIAL 5
TABLE B
-------
NAME FOLDER_ACCESS R_IDN
FOLDER1 ALL
FOLDER2 ALL
FOLDER3 PARTIAL 5
FOLDER4 PARTIAL 1
FOLDER5 PARTIAL 2
FOLDER5 ALL
WHEN USER 1 Logs IN he has no restriction I should SHOW Folder1-5 .
WHEN USER 2 Logs IN he should NOT see FOLDER 3 (ALL AND 1,2 is fine for view)
WHEN USER 3 Logs IN he should see FOLDER 1, FOLDER 2 , FOLDER3, FOLDER5
The thing is I need to have a WHERE clause conditionally like this :
SELECT DISTINCT NAME * FROM TABLE B
PSEUDO CODE
IFF USER_LOGGED IN HAVING 'ALL' in TABLE A
DO NOTHING
ELSE IFF ITS PARTIAL
WHERE FOLDER_ACESS IS "ALL" OR R_IDN in (TABLEA.R_IDN FOR HIM) .
Is such construcuts possible in SQL ? Its more for an academic understanding of what is possible and what is not . I know to solve this query by breaking it seperately , however want to see if there are tricky solutions for this . And if its worth pursing single hit tricky solutions .
Targetted platforms are ORACLE and MSSQL . However any SQL platform solutions are welcome .

This would do it - you just need to supply the user you want the results for in the where clause. E.g. for user 2:
SELECT distinct a.user, b.name
FROM TABLEA a
INNER JOIN TABLEB b ON a.record_idn = b.r_idn
OR a.access = 'ALL'
OR b.folder_access = 'ALL'
WHERE a.user = 2
ORDER BY a.user, b.name

Is this what you're trying to achieve?
SELECT NAME
FROM B
WHERE EXISTS (
SELECT *
FROM A
WHERE A.USER = #userId
AND (A.ACCESS = 'ALL'
OR B.FOLDER_ACCESS = 'ALL'
OR (A.ACCESS = 'PARTIAL' AND A.RECORD_IDN = B.R_IDN)
)
)
GROUP BY NAME
For MS SQL there's an option to use CROSS APPLY
SELECT NAME
FROM B
CROSS APPLY (
SELECT 1
FROM A
WHERE A.USER = #userId
AND (A.ACCESS = 'ALL'
OR B.FOLDER_ACCESS = 'ALL'
OR (A.ACCESS = 'PARTIAL' AND A.RECORD_IDN = B.R_IDN)
)
)
GROUP BY NAME

Related

Subquery SQL for link name and firstname

Hello I would like to retrieve the name and the first name in the user table thanks to the id contained in the message table (id_receive and id_send) in sql via a subquery
SELECT user.nom FROM user
WHERE user.id IN (
SELECT message.id_send, message.id_receive FROM message WHERE message.id=1
)
```
I would recommend using EXISTS, twice:
SELECT u.nom
FROM user u
WHERE EXISTS (SELECT 1 FROM message m WHERE m.id = 1 AND u.id = id_send) OR
EXISTS (SELECT 1 FROM message m WHERE m.id = 1 AND u.id = id_receive) ;
However, a JOIN might also be appropriate:
SELECT u.nom
FROM user u JOIN
message m
ON u.id IN (m.id_send, id_receive)
WHERE m.id = 1;
I suspect it isn't actually what you want but it looks like this is what you're trying to do:
SELECT user.nom FROM user
WHERE user.id IN (
SELECT message.id_send FROM message WHERE message.id=1
UNION ALL
SELECT message.id_receive FROM message WHERE message.id=1
)
The query that drives the IN should return a single column of values
Try and conceive that in works like this:
SELECT * FROM t WHERE c IN(
1
2
3
)
Not like this:
SELECT * FROM t WHERE c IN(
1 2 3
)
Nor like this:
SELECT * FROM t WHERE c IN(
1 2 3
4 5 6
)
It might help you reember that the query inside it must return a single column, but multiple rows, all of qhich are searched for a matching value c by IN
Small addition to your original query to make it working:
SELECT user.nom FROM user
WHERE user.id IN (
SELECT unnest(array[message.id_send, message.id_receive])
FROM message
WHERE message.id=1
)

How to write a query to get data count with combination of codision

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)
)

How to get first entry with a value from an hierarchical setting structure?

I have a couple of tables. One table with Groups:
[ID] - [ParentGroupID]
1 - NULL
2 1
3 1
4 2
And another with settings
[Setting] - [GroupId] - [Value]
Title 1 Hello
Title 2 World
Now I'd like to get "Hello" back if I'd query the Title for Group 3
And I'd like to get "World" back if I'd query the Title for Group 4 (And not "Hello" as well)
Is there any way to efficiently do this in MSSQL? At the moment I am resolving this recursively in code. But I was hoping that SQL could solve this problem for me.
Don't knoww the SQL Server syntax but something like the following?
SELECT settings.value
FROM settings
JOIN groups ON settings.groupid = groups.parentgroupid
WHERE settings.setting = 'Title'
AND groups.id = 3
This is a problem we've encountered multiple times in our company. This would work for any case, including when the settings can be set only at some levels and not others (see SQL Fiddle http://sqlfiddle.com/#!3/16af0/1/0 :
With GroupSettings(group_id, parent_group_id, value, current_level)
As
(
Select g.id as group_id, g.parent_id, s.value, 0 As current_Level
From Groups As g
Join Settings As s On s.group_id = g.id
Where g.parent_id Is Null
Union All
Select g.id, g.parent_id, Coalesce((Select value From Settings s Where s.group_id=g.id), gs.value), current_level+1
From GroupSettings as gs
Join Groups As g On g.parent_id = gs.group_id
)
Select *
From GroupSettings
Where group_id=4
I believe the following is what you are seeking. See the sqlfiddle
SELECT vALUE FROM
Groups g inner join Settings s
ON g.ParentGroupId = s.GroupID
WHERE g.ID = 3 -- will return Hello,], set ID = 4 will return World

SQL - Linked information

I have a database table, which a program is about to update. I have taken a snapshot of the table before the program ran and a snapshot afterwards. Here is a sample of the data:
Before update:
JoinReference User
1 User 1
1 User 2
1 User 3
2 User 4
2 User 5
2 User 6
After update:
JoinReference User
3 User 1
3 User 2
3 User 3
4 User 4
4 User 5
5 User 6
I am trying to find all the users that are not linked together after the update. For example, user 1; user 2 and user 3 are linked before and after the update (even though they have a different join reference). User 4 and five are still linked after the update. User 6 is not linked after the update. I am trying to return user 6 after the update. I have tried using derived tables but it has not worked.
This is for a very large database. The example I have given uses fields I have made up to explain the problem. The database structure for the example would be like this:
CREATE TABLE JoinedUsers (JoinReference int, User)
select UnpairedBefore.userid
from
(select main.*
from tableBefore main
left join tableBefore ref
on main.joinreference = ref.joinreference
and main.userid <> ref.userid
where ref.userid null) UnpairedBefore
inner join
(select main.*
from tableAfter main
left join tableAfter ref
on main.joinreference = ref.joinreference
and main.userid <> ref.userid
where ref.userid null) UnpairedAfter
on UnpairedBefore.userid = UnpairedAfter.userid
or
select [user]
from tblBefore
where JoinReference in
(
select JoinReference
from tblBefore
group by JoinReference
having COUNT(*) = 1
)
and [user] in
(
select [user]
from tblAfter
where JoinReference in
(
select JoinReference
from tblAfter
group by JoinReference
having COUNT(*) = 1
)
)
You want something along the lines of
SELECT *
FROM myTable
WHERE (row_was_updated)
AND JoinReference IN
(SELECT JoinReference
FROM myTable
GROUP BY JoinReference
HAVING COUNT(*) = 1)
You may or may not need WHERE (row_was_updated) and you'll have to fill in that logic yourself if you need it.
It's likely there would be a more efficient way of doing that, but without schema it's only possible to give general guidance.
SELECT b1.user AS user1
, b2.user AS user2
FROM BeforeTable AS b1 --- user1 and
JOIN BeforeTable AS b2 --- user2 were linked
ON b1.JoinReference = b2.JoinReference --- before the update
WHERE b1.user < b2.user
AND NOT EXISTS --- and are not linked
( SELECT *
FROM AfterTable AS a1 --- after the update
JOIN AfterTable AS a2
ON a1.JoinReference = a2.JoinReference
WHERE a1.user = b1.user
AND a2.user = b2.user
) ;

SQL Elaborate Joins Query

I'm trying to solve the below problem.
I feel like it is possible, but I can't seem to get it.
Here's the scenario:
Table 1 (Assets)
1 Asset-A
2 Asset-B
3 Asset-C
4 Asset-D
Table 2 (Attributes)
1 Asset-A Red
2 Asset-A Hard
3 Asset-B Red
4 Asset-B Hard
5 Asset-B Heavy
6 Asset-C Blue
7 Asset-C Hard
If I am looking for something having the same attributes as Asset-A, then it should identify Asset-B since Asset-B has all the same attributes as Asset-A (it should discard heavy, since Asset-A didn't specify anything different or the similar). Also, if I wanted the attributes for only Asset-A AND Asset-B that were common, how would I get that?
Seems simple, but I can't nail it...
The actual table I am using, is almost precisely Table2, simply an association of an AssetId, and an AttributeId so:
PK: Id
int: AssetId
int: AttributeId
I only included the idea of the asset table to simplify the question.
SELECT ato.id, ato.value
FROM (
SELECT id
FROM assets a
WHERE NOT EXISTS
(
SELECT NULL
FROM attributes ata
LEFT JOIN
attributes ato
ON ato.id = ata.id
AND ato.value = ata.value
WHERE ata.id = 1
AND ato.id IS NULL
)
) ao
JOIN attributes ato
ON ato.id = ao.id
JOIN attributes ata
ON ata.id = 1
AND ata.value = ato.value
, or in SQL Server 2005 (with sample data to check):
WITH assets AS
(
SELECT 1 AS id, 'A' AS name
UNION ALL
SELECT 2 AS id, 'B' AS name
UNION ALL
SELECT 3 AS id, 'C' AS name
UNION ALL
SELECT 4 AS id, 'D' AS name
),
attributes AS
(
SELECT 1 AS id, 'Red' AS value
UNION ALL
SELECT 1 AS id, 'Hard' AS value
UNION ALL
SELECT 2 AS id, 'Red' AS value
UNION ALL
SELECT 2 AS id, 'Hard' AS value
UNION ALL
SELECT 2 AS id, 'Heavy' AS value
UNION ALL
SELECT 3 AS id, 'Blue' AS value
UNION ALL
SELECT 3 AS id, 'Hard' AS value
)
SELECT ato.id, ato.value
FROM (
SELECT id
FROM assets a
WHERE a.id <> 1
AND NOT EXISTS
(
SELECT ata.value
FROM attributes ata
WHERE ata.id = 1
EXCEPT
SELECT ato.value
FROM attributes ato
WHERE ato.id = a.id
)
) ao
JOIN attributes ato
ON ato.id = ao.id
JOIN attributes ata
ON ata.id = 1
AND ata.value = ato.value
I don't completely understand the first part of your question, identifying assets based on their attributes.
Making some assumptions about column names, the following query would yield the common attributes between Asset-A and Asset-B:
SELECT [Table 2].Name
FROM [Table 2]
JOIN [Table 1] a ON a.ID = [Table 2].AssetID AND a.Name = 'Asset-A'
JOIN [Table 1] b ON b.ID = [Table 2].AssetID AND b.Name = 'Asset-B'
GROUP BY [Table 2].Name
Select * From Assets A
Where Exists
(Select * From Assets
Where AssetId <> A.AssetID
And (Select Count(*)
From Attributes At1 Join Attributes At2
On At1.AssetId <> At2.AssetId
And At1.attribute <> At2.Attribute
Where At1.AssetId = A.AssetId Asset) = 0 )
And AssetId = 'Asset-A'
select at2.asset, count(*)
from attribute at1
inner join attribute at2 on at1.value = at2.value
where at1.asset = "Asset-A"
and at2.asset != "Asset-A"
group by at2.asset
having count(*) = (select count(*) from attribute where asset = "Asset-A");
Find all assets who have every attribute that "A" has (but also may have additional attributes):
SELECT Other.ID
FROM Assets Other
WHERE
Other.AssetID <> 'Asset-A' -- do not return Asset A as a match to itself
AND NOT EXISTS (SELECT NULL FROM Attributes AttA WHERE
AttA.AssetID='Asset-A'
AND NOT EXISTS (SELECT NULL FROM Attributes AttOther WHERE
AttOther.AssetID=Other.ID AND AttOther.AttributeID = AttA.AttributeID
)
)
I.e., "find any asset where there is no attribute of A that is not also an attribute of this asset".
Find all assets who have exactly the same attributes as "A":
SELECT Other.ID
FROM Assets Other
WHERE
Other.AssetID <> 'Asset-A' -- do not return Asset A as a match to itself
AND NOT EXISTS (SELECT NULL FROM Attributes AttA WHERE
AttA.AssetID='Asset-A'
AND NOT EXISTS (SELECT NULL FROM Attributes AttOther WHERE
AttOther.AssetID=Other.ID
AND AttOther.AttributeID = AttA.AttributeID
)
)
AND NOT EXISTS (SELECT NULL FROM Attributes AttaOther WHERE
AttaOther.AssetID=Other.ID
AND NOT EXISTS (SELECT NULL FROM Attributes AttaA WHERE
AttaA.AssetID='Asset-A'
AND AttaA.AttributeID = AttaOther.AttributeID
)
)
I.e., "find any asset where there is no attribute of A that is not also an attribute of this asset, and where there is no attribute of this asset that is not also an attribute of A."
This solution works as prescribed, thanks for the input.
WITH Atts AS
(
SELECT
DISTINCT
at1.[Attribute]
FROM
Attribute at1
WHERE
at1.[Asset] = 'Asset-A'
)
SELECT
DISTINCT
Asset,
(
SELECT
COUNT(ta2.[Attribute])
FROM
Attribute ta2
INNER JOIN
Atts b
ON
b.[Attribute] = ta2.[attribute]
WHERE
ta2.[Asset] = ta.Asset
)
AS [Count]
FROM
Atts a
INNER JOIN
Attribute ta
ON
a.[Attribute] = ta.[Attribute]
Find all assets that have all the same attributes as asset-a:
select att2.Asset from attribute att1
inner join attribute att2 on att2.Attribute = att1.Attribute and att1.Asset <> att2.Asset
where att1.Asset = 'Asset-A'
group by att2.Asset, att1.Asset
having COUNT(*) = (select COUNT(*) from attribute where Asset=att1.Asset)
I thought maybe I can do this with LINQ and then work my way backwards with:
var result = from productsNotA in DevProducts
where productsNotA.Product != "A" &&
(
from productsA in DevProducts
where productsA.Product == "A"
select productsA.Attribute
).Except
(
from productOther in DevProducts
where productOther.Product == productsNotA.Product
select productOther.Attribute
).Single() == null
select new {productsNotA.Product};
result.Distinct()
I thought that translating this back to SQL with LinqPad would result into a pretty SQL query. However it didn't :). DevProducts is my testtable with a column Product and Attribute. I thought I'd post the LINQ query anyways, might be useful to people who are playing around with LINQ.
If you can optimize the LINQ query above, please let me know (it might result in better SQL ;))
I'm using following DDL
CREATE TABLE Attributes (
Asset VARCHAR(100)
, Name VARCHAR(100)
, UNIQUE(Asset, Name)
)
Second question is easy
SELECT Name
FROM Attributes
WHERE Name IN (SELECT Name FROM Attributes WHERE Asset = 'A')
AND Asset = 'B'
First question is not more difficult
SELECT Asset
FROM Attributes
WHERE Name IN (SELECT Name FROM Attributes WHERE Asset = 'A')
GROUP BY Asset
HAVING COUNT(*) = (SELECT COUNT(*) FROM FROM Attributes WHERE Asset = 'A')
Edit:
I left AND Asset != 'A' out of the WHERE clause of the second snippet for brevity