Select from Multiple tables using Where, Max and SUM functions - sql

I'm trying to get the following results,
based on my current WHERE statement I get several records which are from the same project_id, I'm interested in the latest based on id
from the second table I get multiple rows due to amount field, this could have several entries some additive or deductive. I would like to sum this amount and separate the deductive and additive
all of these resulst I want grouped by project_id so that I only have one row for each project_id
Table uco1
project_id
OrigProjName_TB
status
id
Table ucoline
record_id
amount
SELECT
a.project_id,
a.OrigProjName_TB,
a.CO_NewContract_CA,
a.con_amount_ca,
a.co_changeorderdate_do,
a.co_changeid_tb,
a.co_thiscoamount_ca,
a.OrigProjID_TB,
a.PIF_SpecNumber_TB,
a.CO_TITLE_TB,
a.status,
b.amount
FROM unifier_uco1 a
LEFT JOIN unifier_uco1_lineitem b
ON a.id = b.record_id
WHERE a.status = 'Authorized' OR a.status = 'Ratified'
What I have so far is this...
project_id
OrigProjName_tb
status
id
record_id
amount
2103
demo2
Authorized
786
786
142418
2103
demo2
Authorized
832
832
-523961
2103
demo2
Authorized
784
784
458228
2103
demo2
Authorized
784
784
67565
2100
demo3
Ratified
774
774
-852.85
2100
demo3
Ratified
774
774
4557
What I would like to see is the following;
project_id
OrigProjName_tb
status
id
record_id
additive
deductive
2103
demo2
Authorized
832
832
-523961
2100
demo3
Ratified
774
774
4557
-852.85
unfortunately for me I'm very new at this and just know a couple of basic functions. I even tried creating separate tables with basic functions to try and split up each function and later try to join all into one. This also resulted in a mess since I'm not familiar with all the different functions and statements.
I appreciate your help in advance and also, if you can provide best place to learn I would greatly appreciate that as well.
Thanks,

Related

SQL Code to Update Entities with the same ID

We have an app to manage our Member's information that is tied to a SQL Database. We have attributes that the users can set that apply to the whole family. I am trying to write a SQL Script that will update the values for the whole family.
Example:
Here is a sample of a few columns of our dbo.AttributeValue column:
AttributeID
EntityID
Value
CreatedDateTime
ModifiedDateTime
5856
733
True
2021-11-06 17:30:38.207
2021-11-10 13:52:09.843
5856
613
Fale
2021-11-05 12:12:08.207
2021-11-16 3:32:01.843
Here is a sample of a few columns in our dbo.Person Table:
ID
PrimaryFamilyID
733
187
709
187
137
187
I would like for anyone with the same value in PrimaryFamilyID to have the same values in the dbo.AttributeValue table. Bonus points if we can make it update to the value with the most recent ModifiedDateTime in the dbo.AttributeValue table so that if someone in the family modifies the value after every has an assigned attribute, it will go ahead an update those as well.
Desired outcome:
AttributeID
EntityID
Value
CreatedDateTime
ModifiedDateTime
5856
733
True
2021-11-06 17:30:38.207
2021-11-10 13:52:09.843
5856
709
True
2021-11-06 17:30:38.207
2021-11-10 13:52:09.843
5856
137
True
2021-11-06 17:30:38.207
2021-11-10 13:52:09.843
It took me a while to get to a solution what you want is but here it is
DBFiddleRunningSolution
You can start somewhere from here.
With PersonCTE as (
Select Count(*) as cnt,PrimaryFamilyId
from Person
group by PrimaryFamilyId
having count(*)>1
)
Select AV.AttributeId,P.Id,AV.Value,AV.CreatedDateTime,AV.ModifiedDateTime
into NewAttributeValue
from Person P inner join PersonCTE C
ON P.PrimaryFamilyId = C.PrimaryFamilyId
cross join AttributeValue AV
where AV.EntityId in (Select distinct Id from Person)

Including variables after filtering selecting only minimum values in SQL?

I am working with a twin dataset and would like to create a table with the Subject ID (Subject) and twin pair ID (twpair) for the twins with the lower (or one of the twins if the values are equal) lifetime total of marijuana use (MJ1a).
A portion of my table looks like this:
Subject
twpair
MJ1a
156
345
10
157
345
7
158
346
20
159
346
3
160
347
4
161
347
4
I'm hoping to create a table with only the twins that have the lower amount of marijuana use which would look like this:
Subject
twpair
MJ1a
157
345
7
159
346
3
161
347
4
This is the SQL code I have so far:
proc sql;
create table one_twin as
select twpair,min(MJ1a) as minUse, Subject
from twins_deviation
group by twpair;
Unfortunately this ends up causing all of the subjects to be remerged back in the dataset. If I don't include the Subject portion I get the correct values for twpair and MJ1a but not the Subject IDs.
How do I filter the dataset to only include those with the minimum values while also including variables of interest like Subject ID? Note that if two pairs of twins have the SAME value I would like to select one but it doesn't matter which I select. Any tips would be extremely appreciated!
This query should give you the desired result.
select a.subject,a.twpair,a.MJ1a from twins_deviation a join (select twpair,min(mj1a) as mj1a from twins_deviation group by twpair)b on a.twpair=b.twpair and a.mj1a=b.mj1a
If your DB supports analytic/window functions ,the same can be accomplished using a rank function ,solution given below.
EDIT1:to handle same values for mj1a
select subject,twpair,mj1a from(select subject,twpair,mj1a ,row_number() over(partition by twpair order by mj1a) as rnk from twins_deviation)out1 where rnk=1;
EDIT2:Updated solution 1 to include only one twin.
select min(subject) as subject,twpair,mj1a from(select a.subject as subject ,a.twpair as twpair,a.MJ1a as MJ1a from twins_deviation a join (select twpair,min(mj1a) as mj1a from twins_deviation group by twpair)b on a.twpair=b.twpair and a.mj1a=b.mj1a)out1 group by twpair,MJ1a;

Join tables where no common field exists and based on ID columns

This question seems hard to phrase, but after explaining my situation it should be easy to understand. I have two tables: one called INSTRUCTORS that holds instructor data and another called LIST_OPTION_ITEM that holds the ID values of different ID columns stored in the INSTRUCTORS table. A third and possibly important table to include is LIST_OPTION_TYPE, which contains the IDs of whatever ID column there is in INSTRUCTORS. Perhaps it would be easier to explain by showing sample data and my desired output.
INSTRUCTORS
RANK_ID
SPECIALTY_ID
DUTY_TITLE_ID
SERVICE_BRANCH_ID
STATUS_ID
UNIT_ID
OFFICE_SYMBOL_ID
1354
319
931
2604
1378
1406
1429
LIST_OPTION_ITEM
OPTION_ITEM_ID
OPTION_TYPE_ID
ITEM_VALUE
1354
22
CAPT
319
20
CBRN TRAUMA NURSE
931
21
IDMT-Squadron Medical Element
2604
128
46N NURSE
1378
23
USA
1406
24
Guard
1429
126
CERFP
LIST_OPTION_TYPE
OPTION_TYPE_ID
OPTION_TYPE
20
Specialty
21
Duty_Title
22
Rank
23
Service_Branch
24
Status
126
Unit
128
Office_Symbol
It is important to note that I cannot join INSTRUCTORS and LIST_OPTION_ITEM, as there is no common column. However, LIST_OPTION_ITEM and LIST_OPTION_TYPE can join on OPTION_TYPE_ID. My desired output from a SELECT query:
Rank
Specialty
Duty Title
Service Branch
Status
Unit
Office Symbol
CAPT
CBRN TRAUMA NURSE
IDMT-Squadron Medical Element
46N NURSE
USA
Guard
CERFP
I've tried some solutions but can't come up with anything. Do I need a cross join or something? Help would be much appreciated.
I tried to do with Pivot and unpivot functions
below is sample sql:
with inst as (select inst_id, col, col_id
from (select rownum as inst_id, a.* from instructor a)
unpivot
(col_id for col in (status_id as 'STATUS',rank_id as 'RANK',specialty_id as 'SPECIALTY',duty_title_id as 'DUTY_TITLE')
))
select * from
(select inst_id,col,item_value from inst,
(select a.option_type,b.option_item_id,b.item_value from LIST_OPTION_TYPE a, list_option_id b
where a.option_type_id = b.option_type_id) opt
where inst.col = upper(option_type)
and option_item_id = col_id)
pivot
(max(item_value)
for col in ('STATUS','RANK','SPECIALTY','DUTY_TITLE')
) order by inst_id;
this will give desired output

Create column based on grouping other values

I have difficulties formulating my issue.
I have a view which brings these results. There's a need to add a column to the view, which will pair up round-trip flights with identical number.
Flt_No From_Airport To_Airport Dep_Date RequiredResult
124 |LCA |CDG |10/19/14 5:00 1
125 |CDG |LCA |10/19/14 10:00 1
197 |LCA |BCN |10/4/12 5:00 2
198 |BCN |LCA |10/4/12 11:00 2
501 |LCA |HER |15/8/12 12:05 3
502 |HER |LCA |15/8/12 15:15 3
I.e. flight 124 is going from Larnaca to CDG, and flight 125 is going back from CDG to Larnaca - they both have to have the same identifier.
Round-trip flights will always have following flight numbers.
I have a bunch of conditions which I won't write now.
Omitting hours is not an option, they're important.
I was thinking dense_rank() but I don't know how to create one identifier for 2 flights with different numbers, please help.
If your data is similar to the sample data posted, then the following query should give the required result:
SELECT *,
DENSE_RANK() OVER (ORDER BY CASE
WHEN From_Airport < To_Airport THEN From_Airport
ELSE To_Airport
END)
FROM mytable
Join conditions are not limited to simple equality. Assuming {Flight No, Departure, Destination} is unique on any one day, then a self join should do it:
select whatever
from flights outbound
inner join flights inbound on outbound.flt_no+1 = inbound.flt_no
and cast(outbound.dep_date, date)
= cast(inbound.dep_date, date)
and outbound.From_Airport = inbound.To_Airport
and outbound.To_Airpott = inbound.From_Ariport

Ms Access SQL calculation from multiple rows

I have the following query:
SELECT
InspectionID, Distance, Continuous, structural_grade
FROM
Conditions
WHERE
Continuous LIKE ("S%") OR Continuous LIKE ("F%")
ORDER BY
InspectionId ASC, Distance ASC
Which outputs:
262 60.80 S01 3
262 73.10 F01 3
262 82.60 S02 2
262 140.30 F02 2
263 30.80 S01 2
263 46.60 F01 2
380 4.60 S01 3
380 8.50 F01 3
380 9.80 S02 4
380 28.20 F02 4
380 77.70 S03 4
380 97.70 F03 4
The ordering is correct. However I'm stuck at what to do next.
Each "S" has a matching "F" with the same numbers Ex S01, F01. I need to access the Distance field of each "F" and minus "S" distance from it.
For examples F01 has a distance of 73.10 and S01 60.80 so the distance between is 12.3. I need to do this for each records and them numbers after the "S" and "F" can go really high yet will always match. ex. S999 - F999
Use the Mid() function to extract the digits from your Continuous field: Mid("S01", 2) yields "01". Then use those digits when you join the F and S rows.
With your sample data in Access 2010, the following query gave me this result set:
SELECT
f.InspectionID,
f.Continuous,
s.Continuous,
f.Distance AS F_distance,
s.Distance AS S_distance,
f.Distance - s.Distance AS F_minus_S
FROM
Conditions AS f
INNER JOIN
(
SELECT
InspectionID,
Continuous,
Distance,
Mid([Continuous],2) AS digits_only
FROM Conditions
WHERE Continuous ALike 'S%'
) AS s
ON
f.InspectionID = s.InspectionID
AND Mid(f.[Continuous],2) = s.digits_only
WHERE f.Continuous ALike 'F%'
ORDER BY f.InspectionId ASC, f.Distance ASC;
I included several columns which I doubt you want in your final query. But I think they can be useful during development and testing.
Beware the Access query designer will complain it can't represent that join condition in Design View. If you set up the join in SQL View, you can then run the query without Access complaining.
SELECT a.continuous AS 'S Continuous',
a.distance AS 'S Distance',
b.continuous AS 'F Continuous',
b.distance AS 'F Distance',
abs(a.distance - b.distance) AS 'Difference'
FROM Conditions a
INNER JOIN Conditions b
ON a.InspectionID = b.InspectionID
AND substring(a.continuous,2,len(a.continuous)-1) = substring(b.continuous,2,len(b.continuous)-1)
WHERE a.Continuous LIKE 'S%'
AND b.Continuous LIKE 'F%'
ORDER BY a.InspectionId ASC, a.Distance ASC