Multiple row in self join - sql

i have table in this format
Id QId ResourceId ModuleId SubProjId Comments
1 1 1 1 2 ffdg 1 1
2 2 1 1 2 dfgfdg 1 1
3 3 1 1 2 hgjhg 1 1
4 1 2 1 2 tryty 1 0
5 5 1 1 2 sdf 1 1
6 5 2 1 2 ghgfh 1 0
7 7 2 1 2 tytry 1 0
8 3 2 1 2 rytr 1 0
and i wan result in this way
qid ResourceId Comments ResourceId Comments
1 1 ffdg 2 tryty
3 1 hgjhg 2 rytr
i tried
select distinct A.qid,A.ResourceId,A.Comments,B.ResourceId,b.Comments
from dbo.#temp A inner join #temp B on A.QId=B.QId and A.[ModuleId]=B.[ModuleId] and a.[SubProjId]=b.[SubProjId]
but did not find any luck please help

You want to convert vertical data to horizontal. So you need to create a pivot table. You can find more details here
How to transform vertical data into horizontal data with SQL?

Related

SAS - Update table variable with multiple where criteria

Please excuse my lack of knowledge i'm very new to SAS.
I have two tables as exampled below:
T1
ID
Ill_No
1
1
1
1
1
2
1
2
1
3
1
3
2
1
2
1
2
2
2
2
2
3
2
3
T2
ID
Ill_No
1
1
2
3
I want to update the original table with a new variable (MATCH) where both ID and Ill_No match with the second table. Example below:
T1
ID
Ill_No
MATCH
1
1
Y
1
1
Y
1
2
1
2
1
3
1
3
2
1
2
1
2
2
2
2
2
3
Y
2
3
Y
What is the most efficient way to do this?
Perhaps use a simple merge statement
data want;
merge t1(in=one) t2(in=two);
by id III_No;
if one and two then match = 'Y';
run;
ID III_No match
1 1 Y
1 1 Y
1 2
1 2
1 3
1 3
2 1
2 1
2 2
2 2
2 3 Y
2 3 Y

SQL append data based on multiple dates

I have two tables; one contains encounter dates and the other order dates. They look like this:
id enc_id enc_dt
1 5 06/11/20
1 6 07/21/21
1 7 09/15/21
2 2 04/21/20
2 5 05/05/20
id enc_id ord_dt
1 1 03/7/20
1 2 04/14/20
1 3 05/15/20
1 4 05/30/20
1 5 06/12/20
1 6 07/21/21
1 7 09/16/21
1 8 10/20/21
1 9 10/31/21
2 1 04/15/20
2 2 04/21/20
2 3 04/30/20
2 4 05/02/20
2 5 05/05/20
2 6 05/10/20
The order and encounter date can be the same, or differ slightly for the same encounter ID. I'm trying to get a table that contains all order dates before each encounter date. So the data would like this:
id enc_id enc_dt enc_key
1 1 03/7/20 5
1 2 04/14/20 5
1 3 05/15/20 5
1 4 05/30/20 5
1 5 06/11/20 5
1 1 03/7/20 6
1 2 04/14/20 6
1 3 05/15/20 6
1 4 05/30/20 6
1 5 06/12/20 6
1 6 07/21/21 6
1 1 03/7/20 7
1 2 04/14/20 7
1 3 05/15/20 7
1 4 05/30/20 7
1 5 06/12/20 7
1 6 07/21/21 7
1 7 09/15/21 7
2 1 04/15/20 2
2 2 04/21/20 2
2 1 04/15/20 5
2 2 04/21/20 5
2 3 04/30/20 5
2 4 05/02/20 5
2 5 05/05/20 5
Is there a way to do this? I am having trouble figuring out how to append the orders and encounter table for each encounter based on orders that occur before a certain date.
You may join the two tables as the following:
SELECT O.id, O.enc_id, O.ord_dt, E.enc_id
FROM
order_tbl O
JOIN encounter_tbl E
ON O.ord_dt <= E.enc_dt AND
O.id = E.id
See a demo from db<>fiddle.

Sum distinct group values only

I would like to sum values distinct per group. Pardon the wordy post...
Context. Suppose I have a table of the form:
ID Foo Value
A 1 2
B 0 2
C 0 3
A 1 2
A 1 2
C 0 3
B 0 2
Each ID/Foo combo has a distinct value. I'd like to join this table onto another cte that has a cumulative field, e.g. suppose after joining using rows unbounded preceeding I have a new field called cumulative. Same data, just duplicated 3 times with value cumulative:
ID Foo Value Cumulative
A 1 2 1
B 0 2 1
C 0 3 1
A 1 2 1
A 1 2 1
C 0 3 1
B 0 2 1
A 1 2 2
B 0 2 2
C 0 3 2
A 1 2 2
A 1 2 2
C 0 3 2
B 0 2 2
A 1 2 3
B 0 2 3
C 0 3 3
A 1 2 3
A 1 2 3
C 0 3 3
B 0 2 3
I want to add a new field 'segment_value' that, for each foo gets the sum of distinct ID values. E.g. The distinct ID/Foo combinations are:
ID Foo Value
A 1 2
B 0 2
C 0 3
I would therefore like a new field, 'segment_value', That returns 2 for Foo=1 and 5 for Foo=0. Desired result:
ID Foo Value Cumulative segment_value
A 1 2 1 2
B 0 2 1 5
C 0 3 1 5
A 1 2 1 2
A 1 2 1 2
C 0 3 1 5
B 0 2 1 5
A 1 2 2 2
B 0 2 2 5
C 0 3 2 5
A 1 2 2 2
A 1 2 2 2
C 0 3 2 5
B 0 2 2 5
A 1 2 3 2
B 0 2 3 5
C 0 3 3 5
A 1 2 3 2
A 1 2 3 2
C 0 3 3 5
B 0 2 3 5
How can I achieve this?
I don't think you explained your problem very well and I might have misunderstood something, but can't you extract the segment_value using a query such as this one:
select
foo,
sum(val) as segment_value
from (
select distinct foo, val from table
) tab
group by foo
this would return the following result:
foo segment_value
1 2
0 5
then you could join this to the rest of you query and use it as per your needs.

SQL Insert distinct records

I'm trying to batch some insertion scripts (avoiding duplicates) and I've come across some tables that have no primary key (I know...I didn't create them and I cannot modify them). Basically what I've done is grabbed the rows I need, put them into a temporary table ([TempTable]), and updated some values in them.
Now I need to re-insert DISTINCT TOP values from [TempTable] into [OriginalTable] in batches. To do this, I imagine I would need a column in the temp table (which I've created...let's call it [ValuesInserted]), that specifies which columns were just inserted.
I would do an INSERT statement to put DISTINCT values into the original table, using TOP to batch it.
INSERT INTO [OriginalTable]
SELECT DISTINCT TOP (1000) *
FROM [TempTable]
Then I would UPDATE the temp table to have ValuesInserted set to 1 for the records that were just inserted. This is where I'm stuck:
UPDATE /*TOP (1000) - Doesn't work*/ [TempTable]
SET [ValuesInserted] = 1
???
Then I would DELETE those records from the temp table so that my next INSERT statement (using TOP) will not capture the previous set of records.
DELETE
FROM [TempTable]
WHERE [ValuesInserted] = 1
The main problem I'm having is that just running an UPDATE on just the TOP (1000) rows, doesn't capture all of the records that may have duplicates in [TempTable]. I also cannot perform an INNER JOIN on all columns on two copies of [TempTable] because this is being run on many different tables using dynamic SQL. Basically, the script needs to be generic (not specific to any table), but it should be assumed that there is no primary key.
The following generic sample captures the idea:
Val1 Val2 ValuesInserted
1 1 0
1 2 0
1 3 0
1 4 0
1 5 0
1 6 0
1 7 0
1 8 0
1 9 0
1 1 0 <--Duplicate
2 1 0
2 2 0
2 3 0
2 4 0
2 5 0
2 6 0
2 7 0
2 8 0
2 9 0
2 1 0 <--Duplicate
3 1 0
3 2 0
3 3 0
3 4 0
3 5 0
3 6 0
3 7 0
3 8 0
3 9 0
3 1 0 <--Duplicate
1 2 0 <--Duplicate
1 3 0 <--Duplicate
Doing an UPDATE TOP (5) on this above data set will only update the first 5 records:
Val1 Val2 ValuesInserted
1 1 1 <--Updated
1 2 1 <--Updated
1 3 1 <--Updated
1 4 1 <--Updated
1 5 1 <--Updated
1 6 0
1 7 0
1 8 0
1 9 0
1 1 0 <--Duplicate
2 1 0
2 2 0
2 3 0
2 4 0
2 5 0
2 6 0
2 7 0
2 8 0
2 9 0
2 1 0 <--Duplicate
3 1 0
3 2 0
3 3 0
3 4 0
3 5 0
3 6 0
3 7 0
3 8 0
3 9 0
3 1 0 <--Duplicate
1 2 0 <--Duplicate
1 3 0 <--Duplicate
I need to update any records that match the top 5 records like so:
Val1 Val2 ValuesInserted
1 1 1 <--Updated
1 2 1 <--Updated
1 3 1 <--Updated
1 4 1 <--Updated
1 5 1 <--Updated
1 6 0
1 7 0
1 8 0
1 9 0
1 1 1 <--Updated
2 1 0
2 2 0
2 3 0
2 4 0
2 5 0
2 6 0
2 7 0
2 8 0
2 9 0
2 1 0 <--Duplicate
3 1 0
3 2 0
3 3 0
3 4 0
3 5 0
3 6 0
3 7 0
3 8 0
3 9 0
3 1 0 <--Duplicate
1 2 1 <--Updated
1 3 1 <--Updated
If you can make your idea work on this sample, I can apply it to my specific case.
Am I approaching this completely wrong, or am I missing something? I'm looking for a solution that doesn't hog resources because the script is batched and is running on very large databases on high-impact servers.
The closest topic I could find on this was:
Using Distinct in SQL Update.
However, the answers given would not work when using TOP.
EDIT: This apparently wasn't clear at the beginning. The first thing I'm doing is grabbing rows from [OriginalTable] and putting them into [TempTable]. These rows are initially unique. However, I perform an update that modifies some of the values, yielding data like the sample above. From there, I need to grab DISTINCT rows and re-insert them into [OriginalTable].
It looks like you're really going out of your way to make this as complicated as possible. I would just remove the duplicates from the temporary table in the first place. Or never INSERT them there, which is even better. Or build an actual ETL solution, perhaps with SSIS.
Those things said, what you're looking for is the OUTPUT clause, which can be added to any INSERT, UPDATE, or DELETE statement:
DECLARE #inserted_ids TABLE (val1, val2)
INSERT INTO dbo.OriginalTable (val1, val2)
OUTPUT INSERTED.val1, INSERTED.val2 INTO #inserted_ids
SELECT DISTINCT TOP 1000 val1, val2
FROM dbo.TempTable
DELETE TT
FROM #inserte_ids II
INNER JOIN dbo.TempTable TT ON
TT.val1 = II.val1 AND
TT.val2 = II.val2

Which type of join can I use to reproduce these results

I have the following view which contains this data
ActivityRecId RegionRecId IsExcluded
1 null 1
2 null 1
3 1 1
3 2 1
4 1 1
5 null 0
What I would like to do is join the region table to the view above to get the following records.
ActivityRecId RegionRecId IsExcluded
1 null 1
2 null 1
3 1 1
3 2 1
3 3 0
3 4 0
4 1 1
4 2 0
4 3 0
4 4 0
5 null 0
The region table has the following columns:
RegionRecId
RegionName
Any suggestions. Let me know if you need any other information.
--------------------- CORRECT QUESTION ------------------------
ActivityRecId RegionRecId IsExcluded
1 null 1
2 null 1
3 1 1
3 2 1
3 3 0
3 4 0
4 1 1
4 2 0
4 3 0
4 4 0
5 1 0
5 2 0
5 3 0
5 4 0
If it makes it easier activity 1 and 2 can list all the regions also.
Thanks,
I don't have an SQL Server handy to test this, but would something like
select *
from myView
union
select myView.ActivityRecId,
region.RegionRecId,
0 as IsExcluded
from myView cross join region
where (myView.RegionRecId is not null or myView.IsExcluded = 0)
and not exists (
select null
from myView
where myView.RegionRecId = region.RegionRecId
)
be what you want?
Here's great reference to take a look at for joins. I think you'd need a Left Outer Join