Getting ID1s that doesn't have occurrences on group of ID2s - postgresql

Suppose I have two columns, ID1 and ID2. I want the query to return ID values where it doesn't have any occurrences of group of ID2s.
ID1 ID2
1 3
1 4
1 5
2 1
2 3
3 1
3 6
4 4
4 7
5 1
5 8
Suppose I want ID1 to return IDs which doesn't have (3,4,5) values, the result should be 3,5 here.
What should be the query in postgresql?
Thanks

You can use the following query:
SELECT ID1
FROM mytable
GROUP BY ID1
HAVING COUNT(CASE WHEN ID2 IN(3,4,5) THEN 1 END) = 0
Demo here
This will return ID1 values that are not related to even one ID2 value contained in (3,4,5).

With a table created like this:
CREATE TABLE temp
(
id1 integer,
id2 integer
);
insert into temp values(1,3);
insert into temp values(1,4);
insert into temp values(1,5);
insert into temp values(2,1);
insert into temp values(2,3);
insert into temp values(3,1);
insert into temp values(3,6);
insert into temp values(4,4);
insert into temp values(4,7);
insert into temp values(5,1);
insert into temp values(5,8);
The query for the example is just:
select distinct a.id1 from temp a where a.id1 not in (select b.id1 from temp b where b.id2 in (3,4,5) and b.id1 is not null)

Related

Concatenate JSON rows

I have the following table with sample records:
create table jtest
(
id int,
jcol json
);
insert into jtest values(1,'{"name":"Jack","address1":"HNO 123"}');
insert into jtest values(1,'{"address2":"STREET1"}');
insert into jtest values(1,'{"address3":"UK"}');
select * from jtest;
id jcol
-------------------------------------------
1 {"name":"Jack","address":"HNO 123 UK"}
1 {"address2":"STREET1"}
1 {"address3":"UK"}
Expected result:
id jcol
--------------------------------------------------------------------------------------------
1 {"name":"Jack","address":"HNO 123 UK", "address2":"STREET1", "address3":"UK"}
Tried the following query:
select id,json_agg(jcol) as jcol
from jtest
group by id;
But getting result is unexpected:
id jcol
--------------------------------------------------------------------------------------------
1 [{"name":"Jack","address":"HNO 123 UK"}, {"address2":"STREET1"}, {"address3":"UK"}]
demo:db<>fiddle
SELECT
id,
json_object_agg(key, value) -- 2
FROM
t,
json_each(jcol) -- 1
GROUP BY id
First you have to extract all elements into one row
Afterwards you can reaggregate all of them

Remove duplicate with separate column check TSQL

I have 2 tables having same columns and permission records in it.
One columns named IsAllow is available in both tables.
I am getting records of both tables in combine using UNION
But want to skip similar records if IsAllow = 0 in any one column - I don't want those records. But UNION returns all records and am getting confused.
Below are columns
IsAllow, UserId, FunctionActionId
I tried union but it gives both records. I want to exclude IsAllow = 0 in either table.
Sample data table 1
IsAllow UserId FunctionActionId
1 2 5
1 2 8
Sample data table 2
IsAllow UserId FunctionActionId
0 2 5 (should be excluded)
1 2 15
You can try this:
;with cte as(select *, row_number()
over(partition by UserId, FunctionActionId order by IsAllow desc) rn
from
(select * from table1
union all
select * from table2) t)
select * from cte where rn = 1 and IsAllow = 1
Version2:
select distinct coalesce(t1.UserId, t2.UserId) as UserId,
coalesce(t1.FunctionActionId, t2.FunctionActionId) as FunctionActionId,
1 as IsAllow
from tabl1 t1
full join table2 t2 on t1.UserId = t2.UserId and
t1.FunctionActionId = t2.FunctionActionId
where (t1.IsAllow = 1 and t2.IsAllow = 1) or
(t1.IsAllow = 1 and t2.IsAllow is null) or
(t1.IsAllow is null and t2.IsAllow = 1)

TSQL Update value to 1 if Max value between two table else 0

I have two table
TABLE 1 : Stage_product
PRODUCT_ID SYS_ROWDATETIMEUTC
1 2015-03-13 06:09:30.040
2 ....
3
TABLE 2 : DIM_Product
PRODUCT_ID SYS_ROWSTARTDATETIMEUTC SYS_ROWISCURRENT
1 2014-03-13 06:09:30.040 0
2 2015-03-13 06:09:30.040 1
I want to do an update statement that if the value SYS_ROWDATETIMEUTC in the first table is more recent than the value SYS_ROWSTARTDATETIMEUTC in the table, then the value SYS_ROWISCURRENT in the second table is set to 0, else 1.
You can use the following query:
UPDATE t2
SET t2.SYS_ROWISCURRENT = CASE
WHEN t1.SYS_ROWDATETIMEUTC > t2.SYS_ROWSTARTDATETIMEUTC THEN 0
ELSE 1
END
FROM Table2 t2
INNER JOIN Table1 t1 ON t2.PRODUCT_ID = t1.PRODUCT_ID
I assume you want to compare dates between the two tables for the same product.

T-SQL query, multiple values in a field

I have two tables in a database. The first table tblTracker contains many columns, but the column of particular interest is called siteAdmin and each row in that column can contain multiple loginIDs of 5 digits like 21457, 21456 or just one like 21444. The next table users contains columns like LoginID, fname, and lname.
What I would like to be able to do is take the loginIDs contained in tblTracker.siteAdmin and return fname + lname from users. I can successfully do this when there is only one loginID in the row such as 21444 but I cannot figure out how to do this when there is more than one like 21457, 21456.
Here is the SQL statement I use for when there is one loginID in that column
SELECT b.FName + '' '' + b.LName AS siteAdminName,
FROM tblTracker a
LEFT OUTER JOIN users b ON a.siteAdmin= b.Login_Id
However this doesn't work when it tries to join a siteAdmin with more than one LoginID in it
Thanks!
I prefer the number table approach to split a string in TSQL
For this method to work, you need to do this one time table setup:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this split function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,')
OUTPUT:
ListValue
-----------------------
1
2
3
4
5
6777
(6 row(s) affected)
Your can now use a CROSS APPLY to split every row in your table like:
DECLARE #users table (LoginID int, fname varchar(5), lname varchar(5))
INSERT INTO #users VALUES (1, 'Sam', 'Jones')
INSERT INTO #users VALUES (2, 'Don', 'Smith')
INSERT INTO #users VALUES (3, 'Joe', 'Doe')
INSERT INTO #users VALUES (4, 'Tim', 'White')
INSERT INTO #users VALUES (5, 'Matt', 'Davis')
INSERT INTO #users VALUES (15,'Sue', 'Me')
DECLARE #tblTracker table (RowID int, siteAdmin varchar(50))
INSERT INTO #tblTracker VALUES (1,'1,2,3')
INSERT INTO #tblTracker VALUES (2,'2,3,4')
INSERT INTO #tblTracker VALUES (3,'1,5')
INSERT INTO #tblTracker VALUES (4,'1')
INSERT INTO #tblTracker VALUES (5,'5')
INSERT INTO #tblTracker VALUES (6,'')
INSERT INTO #tblTracker VALUES (7,'8,9,10')
INSERT INTO #tblTracker VALUES (8,'1,15,3,4,5')
SELECT
t.RowID, u.LoginID, u.fname+' '+u.lname AS YourAdmin
FROM #tblTracker t
CROSS APPLY dbo.FN_ListToTable(',',t.siteAdmin) st
LEFT OUTER JOIN #users u ON st.ListValue=u.LoginID --to get all rows even if missing siteAdmin
--INNER JOIN #users u ON st.ListValue=u.LoginID --to remove rows without any siteAdmin
ORDER BY t.RowID,u.fname,u.lname
OUTPUT:
RowID LoginID YourAdmin
----------- ----------- -----------
1 2 Don Smith
1 3 Joe Doe
1 1 Sam Jones
2 2 Don Smith
2 3 Joe Doe
2 4 Tim White
3 5 Matt Davis
3 1 Sam Jones
4 1 Sam Jones
5 5 Matt Davis
7 NULL NULL
7 NULL NULL
7 NULL NULL
8 3 Joe Doe
8 5 Matt Davis
8 1 Sam Jones
8 15 Sue Me
8 4 Tim White
(18 row(s) affected)

Find duplicate row "details" in table

OrderId OrderCode Description
-------------------------------
1 Z123 Stuff
2 ABC999 Things
3 Z123 Stuff
I have duplicates in a table like the above. I'm trying to get a report of which Orders are duplicates, and what Order they are duplicates of, so I can figure out how they got into the database.
So ideally I'd like to get an output something like;
OrderId IsDuplicatedBy
-------------------------
1 3
3 1
I can't work out how to code this in SQL.
You can use the same table twice in one query and join on the fields you need to check against. T1.OrderID <> T2.OrderID is needed to not find a duplicate for the same row.
declare #T table (OrderID int, OrderCode varchar(10), Description varchar(50))
insert into #T values
(1, 'Z123', 'Stuff'),
(2, 'ABC999', 'Things'),
(3, 'Z123', 'Stuff')
select
T1.OrderID,
T2.OrderID as IsDuplicatedBy
from #T as T1
inner join #T as T2
on T1.OrderCode = T2.OrderCode and
T1.Description = T2.Description and
T1.OrderID <> T2.OrderID
Result:
OrderID IsDuplicatedBy
1 3
3 1