Including variables after filtering selecting only minimum values in SQL? - 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;

Related

How to write a query to return only specified list of rows?

There is a table Shops with Shop_number and Shop Address columns.
Also a table called Properties with two columns:
Shop_number
Property_ID
222222
113
222222
114
222222
115
222223
113
222224
113
222225
111
222226
112
A shop can have more than one property.
How to write a query which would return all shop numbers which does not have Property_ID: 113 at all (excluding 222222, because it indeed has other properties, but also 113).
SELECT p.shop_number FROM Properties p
WHERE p.property_id != 113
My query returns also store 222222 which has 113 property_id.
I would like to return shop numbers: 222225 and 222226 in this case only.
Your description is a bit unclear.
Since you already got an answer how to get your result in case you have to use one of the two tables only, let's have a look on your requirements again which can be read as you need both tables.
You are writing: "A shop can have more than one property. How to write a query which would return all shop numbers which does not have Property_ID: 113 at all"
I don't know if this is your intention, but according to your description, you also want to get all shops that don't even occur at all in the properties table.
So we could use such a query:
SELECT s.shop_number
FROM shops s
WHERE NOT EXISTS
(SELECT 1 FROM properties WHERE property_id = 113
AND shop_number=s.shop_number);
This will show all shop numbers that don't appear at all in the properties table and also all shop numbers that appear having properties different from 113 only.
Only those shop_numbers that occur in the properties table and exist there having the property id 113 will be excluded.
And this is exactly what you described as being your requirement. It's the question if what you told us you want to do is really what you want to do ;)
Either use not exists as #Larnu suggests or use group by / having:
select shopnumber
from t
group by shopnumber
having count(case property_id when 113 then 1 end) = 0;
case maps property_id = 113 to 1 and everything else to null. count(x) does not count rows where x is null.

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

How to select columns of different lengths

I have a table of part numbers along with many of their properties like such:
[Part Number] [Type] [Manager] [Cat. Code] [etc...]
AAA-001 A Dave 123
DDD-008 D Chris 153
BBB-003 B Dave 254
CCC-008 C Dave 153
...
I'm trying to make a list of all the unique values of each property so it looks more like this:
[Type] [Manager] [Cat. Code] [etc...]
A Dave 123
B Chris 153
C 254
D
However whenever I try to do this using SELECT DISTINCT * or the like, it fills up all the columns so that they're the same length as the longest one, filled horizontally according to the original table:
[Type] [Manager] [Cat. Code] [etc...]
A Dave 123
B Dave 254
C Dave 153
D Chris 153
How do I stop this from happening, and just keep unique values of each column, even if they might be different lengths?
I think you've misunderstood what DISTINCT does. It will filter your results so that all rows returned are unique, not each column. Depending which columns are named in your SELECT, you'll get different results. For an example, see http://www.techonthenet.com/sql_server/distinct.php and the section "Example - With Multiple Expressions"
For your case, if you want lists of the unique values in each column, then you'll have to do a separate query on each column, e.g.:
SELECT DISTINCT [Type] FROM [Parts]
SELECT DISTINCT [Manager] FROM [Parts]
...etc
If you then want them side-by-side (as per your sample desired output), you'll just have to copy and paste them into a spreadsheet or something.

Select items where count in another field matches (not updatable)

Here I am trying to get the record for my products where the # swab location in Main table matches the count of swab locations in swab Table and Users can checked off the Y/N to verify that the description of the locations are correct.
Here is the example of my 2 tables.
tblMainEquipment
Asset_ID EquipmentName Num_SwapLocations Verified
234 Saijimon 2 N
235 Pasquale 3 N
tblMainSwapLocations
Asset_ID Swap_location
234 Particle Cannon
234 RailGun
235 Particle Cannon
I use the following query to count the number of records, i avoided using a having query to combine both tables since it is not updatable.
qryMainSwapLocationCount
SELECT MSL.Asset_ID, Count(Asset_ID) AS [Count]
FROM tblMainSwapLocation AS MSL
GROUP BY MSL.Asset_ID;
This will give me the result of
qryMainSwapLocationCount
Asset_ID count
234 2
234 1
I used the following as a record source for my form to allow users to verify the inputs.
SELECT MEQ.Asset_ID, MEQ.Equipment_Name,MEQ.Num_swapLocations MEQ.Verified
FROM tblMainEquipment AS MEQ, qryMainSwapLocationCount AS MSLC
WHERE (((MEQ.Asset_ID)=[MSLC].[Asset_ID]) AND ((MEQ.Num_SwapLocations)=[MSLC].[Count]);
This result would be
tblMainEquipment
Asset_ID EquipmentName Num_SwapLocations Verified
234 Saijimon 2 N
However this record set is not editable. Is there any reasons for this?
I think you should put your table tblMainEquipment as your recordsource and bring all the fields from that on to your form:
Then insert an unbound textbox (perhaps close to your Num_SwapLocations field for easy comparison):
Then in this new textbox, put the following in the ControlSource:
=DCount("ASSET_ID","tblMainSwapLocations","ASSET_ID=" & [Asset_ID])
Then open your form and it should count the number of records in table tblMainSwapLocations that have the same Asset_ID as the record currently showing:
You'll then be able to update the Verified field in your tblMainEquipment table.

DB2 Select from two tables when one table requires sum

In a DB2 Database, I want to do the following simple mathematics using a SQL query:
AvailableStock = SupplyStock - DemandStock
SupplyStock is stored in 1 table in 1 row, let's call this table the Supply table.
So the Supply table has this data:
ProductID | SupplyStock
---------------------
109 10
244 7 edit: exclude this product from the search
DemandStock is stored in a separate table Demand, where demand is logged as each customer logs demand during a customer order journey. Example data from the Demand table:
ProductID | DemandStock
------------------------
109 1
244 4 edit: exclude this product
109 6
109 2
So in our heads, if I want to calculate the AvailableStock for product '109', Supply is 10, Demand for product 109 totals to 9, and so Available stock is 1.
How do I do this in one select query in DB2 SQL?
The knowledge I have so far of some of the imagined steps in PseudoCode:
I select SupplyStock where product ID = '109'
I select sum(DemandStock) where product ID = '109'
I subtract SupplyStock from DemandStock
I present this as a resulting AvailableStock
The results will look like this:
Product ID | AvailableStock
109 9
I'd love to get this selected in one SQL select query.
Edit: I've since received an answer (that was almost perfect) and realised the question missed out some information.
This information:
We need to exclude data from products we don't want to select data for, and we also need to specifically select product 109.
My apologies, this was omitted from the original question.
I've since added a 'where' to select the product and this works for me. But for future sake, perhaps the answer should include this information too.
You do this using a join to bring the tables together and group by to aggregate the results of the join:
select s.ProductId, s.SupplyStock, sum(d.DemandStock),
(s.SupplyStock - sum(d.DemandStock)) as Available
from Supply s left join
Demand d
on s.ProductId = d.ProductId
where s.ProductId = 109
group by s.ProductId, s.SupplyStock;