SQL Server Query for Mutual Matches in the same Table (2012) - sql

We have a table with following columns in Tenants Table.
TenantID
Name
address
Current_Bedrooms
Bedrooms_Needed
Current_City
City_Needed
For a given row, how can we write a query that will find the match the bedrooms_Needed with Current_Bedrooms (same with city) in other rows
example
Select * from Tenants where Current_Bedrooms = Bedrooms_Needed and TenantID = 1234

It sounds like you want the tenants to 'swap' with eachother?
You can join the tenants table with itself (aliased as t1 and t2), while specifying the matching criteria as the join condition:
Select T1.Name As TenantFrom, t2.Name AS TenantTo
from Tenants t1
INNER JOIN Tenants t2
ON t1.Bedrooms_Needed = t2.Current_Bedrooms
AND t1.City_Needed = t2.Current_City
AND t1.TenantID <> t2.TenantID
WHERE t1.TenantID = 1234;
The tenant id exclusion is to prevent self-matches in the event of the tenant living in an exact match already.
Edit, Re Mutual Matches
In order to find pairs of mutually matching tenants, you will need to add the reciprocal criteria as additional filters:
Select T1.Name As TenantFrom, t2.Name AS TenantTo
from Tenants t1
INNER JOIN Tenants t2
ON t1.Bedrooms_Needed = t2.Current_Bedrooms
AND t1.City_Needed = t2.Current_City
AND t1.Current_Bedrooms = t2.Bedrooms_Needed
AND t1.Current_City = t2.City_Needed
AND t1.TenantID <> t2.TenantID
WHERE t1.TenantID = 1234;

Related

How do I update a table's field to be SUM of the field and a different (related) table's field with Sqlite?

I need to update sets.weight to be equal to workout.body_weight + sets.weight for each set.
I have a table sets representing sets of a lift, which belongs to a liftgroup, which belongs to a workout (workout has liftgroups, and each liftgroup has lifts, and each lift has sets). workout.body_weight is my weight on the day I lifted.
sets.weight is the weight I lifted for that particular set.
For weighted pullups I was storing just the weight I was hanging from my body in sets.weight. I want to update this field to be the current value plus my workouts.body_weight on that day.
I've tried a number of suggestions I found in similar questions on SO, but get syntax errors when trying to copy. Possibly this is because Sqlite has a more limited featureset and those answers were for MySQL or PostgreSQL or something.
I've managed to select the relevant data:
SELECT
*
FROM
sets as T1
inner join (
SELECT
workouts.body_weight + sets.weight as new_weight,
sets.id as id
FROM
sets
LEFT JOIN lifts ON sets.lift_id = lifts.id
LEFT JOIN lift_groups ON lifts.lift_group_id = lift_groups.id
LEFT JOIN workouts ON workouts.id = lift_groups.workout_id
WHERE
lifts.lift_id = 5
) T2 ON T1.id = T2.id
This outputs id, lift_id, reps, reps_goal, weight, new_weight, id fields (first 5 are all the fields in sets
All the LEFT JOINs are there to connect a set to the corresponding parent workout just so I can retrieve the workout.body_weight
How can I change this to accomplish what amounts basically to UPDATE sets SET weight = new_weight ?
This ended up working:
UPDATE
sets
SET
weight = (
SELECT
sets.weight + workouts.body_weight as new_weight
FROM
sets T2
INNER JOIN lifts on sets.lift_id = lifts.id
INNER JOIN lift_groups ON lifts.lift_group_id = lift_groups.id
INNER JOIN workouts on workouts.id = lift_groups.workout_id
WHERE
lifts.lift_id = 5
AND sets.id = T2.id
)
where
EXISTS (
SELECT
sets.weight + workouts.body_weight as new_weight
FROM
sets T2
INNER JOIN lifts on sets.lift_id = lifts.id
INNER JOIN lift_groups ON lifts.lift_group_id = lift_groups.id
INNER JOIN workouts on workouts.id = lift_groups.workout_id
WHERE
lifts.lift_id = 5
AND sets.id = T2.id
)
What was throwing me was that in sqlite I cannot begin a query with UPDATE tablename AS alias . . .. Instead, I have to omit the alias, but for the parenthetical SELECT statement I can use one, and then refer to the two tables as tablename and tablealias. Which you can see I did in the snippet.
The first and second parenthetical SELECTS are equivalent. The first generates the new value I want to update to. This gets fed into the UPDATE part. The WHERE EXISTS is just a safeguard to make sure a weight doesn't get set to null if no rows are returned by the SELECT.

Two SQL Queries With Some Overlapping Data

I'm trying to combine two different SQL queries into one table. I've tried various joins and Union but it either duplicates rows or doesn't show all of them.
The first query is
Select
HW.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984
FROM MT_Cireson$AssetManagement$HardwareAsset HW
where HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
This gives all of my hardware assets that have the status I'm looking for.
The second query is:
SELECT
hw.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984,
UB.UPN_7641DFF7_7A20_DC04_FC1C_B6FA8715DA02
FROM MT_Cireson$AssetManagement$HardwareAsset HW
inner join Relationship Rel on HW.BaseManagedEntityId = Rel.SourceEntityId
inner join RelationshipType RT on RT.RelationshipTypeId = Rel.RelationshipTypeId
inner join MT_Microsoft$AD$UserBase UB on UB.BaseManagedEntityId = Rel.TargetEntityId
where RT.RelationshipTypeName = 'Cireson.AssetManagement.HardwareAssetHasPrimaryUser'
and HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
This gives all of the hardware assets I'm looking for that have a primary user configured, but doesn't give the assets without a primary user. I'm not sure how to either A: combine the results just putting in NULL as a primary user for records that don't have one, or B: actually query all the assets at one time and include the primary user column.
I didn't write the second query and I'm not sure exactly how it works. I've tried doing union between the queries but that duplicates the rows because the first query already contains all the elements in the second.
Edit: The PrimaryUser comes from the MT_Microsoft$AD$UserBase table. I've tried adding another column to the first and just setting it as null like:
null as primaryUser,
How about a LEFT JOIN to include all records from HW that are not in UB:
SELECT
hw.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984,
UB.UPN_7641DFF7_7A20_DC04_FC1C_B6FA8715DA02
FROM
MT_Cireson$AssetManagement$HardwareAsset HW
INNER JOIN
Relationship Rel
ON
HW.BaseManagedEntityId = Rel.SourceEntityId
INNER JOIN
RelationshipType RT
ON
RT.RelationshipTypeId = Rel.RelationshipTypeId
LEFT JOIN
MT_Microsoft$AD$UserBase UB
ON
UB.BaseManagedEntityId = Rel.TargetEntityId
WHERE
RT.RelationshipTypeName = 'Cireson.AssetManagement.HardwareAssetHasPrimaryUser'
AND HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
UPDATE:
If the null primary users is what you want, I would recraft the query like:
SELECT
hw.DisplayName,
HW.LocationDetails_0B39A057_2BE8_11B2_BBE2_1E03564AA5CA,
HW.Notes_5CFC0E2A_AB82_5830_D4BB_0596CBED1984,
UB.UPN_7641DFF7_7A20_DC04_FC1C_B6FA8715DA02
FROM
MT_Cireson$AssetManagement$HardwareAsset HW
LEFT JOIN
MT_Microsoft$AD$UserBase UB
ON
HW.BaseManagedEntityId = UB.SourceEntityId
INNER JOIN
RelationshipType RT
ON
RT.RelationshipTypeId = Rel.RelationshipTypeId
INNER JOIN
Relationship Rel
ON
UB.BaseManagedEntityId = Rel.TargetEntityId
WHERE
RT.RelationshipTypeName = 'Cireson.AssetManagement.HardwareAssetHasPrimaryUser'
AND HardwareAssetStatus_3019ADDF_4F3D_2C55_2024_72C22E11F4CF = '866879DF-8FB6-E521-F0E3-FEF86EE1BC92'
I LEFT JOIN'ed HW and UB tables.
As I said earlier, you'll have to tweak the joins. I would try a LEFT JOIN on all tables.
you have an extra column in your 1st query that's why you have duplicates in your union. I would suggest using CTE, there might be other better efficient solutions out there.
;WITH query1
AS
(
SELECT col1, col2
FROM table
),
query2 AS
(
SELECT col1, col2
FROM table
)
SELECT *
FROM cteTable1
UNION ALL
SELECT *
FROM cteTable2
WHERE NOT EXISTS(SELECT * FROM cteTable1 WHERE cteTable1.col1 = cteTable2.col2)

query with left outer join in sql

I have an issue with the below query:
select main.courseid
,main.coursename
,main.catid
,main.catname
,main.need_dte
from (
select t1.courseid
,t1.coursename
,t2.catid
,t2
,catname
,t2.need_dte
from t1
,t2
where t1.courseid = t2.courseid
and t1.coursename = t2.coursename
) main
left outer join (
select courseid
,coursename
,need_dte training_info
) ui on main.courseid = ui.courseid
and main.coursename = ui.coursename
and main.need_dte = ui.need_dte
I have the above scenario in which i am trying to do left outer join between the tables "main" and "training_info".
main table: a inner join between t1 and t2 to get the training and the category details.
training_info(ui): has training details without category details.
here i have few course details in "main" and "ui" tables in common. and i have few unique course records in "main" table not in "ui" table. so i am trying to extract both the unique and common records.
I am able to get the results for this join, but the issue is with the need_dte. the need_dte field is present in both tables.In the result if the records are from "main" table am able to get the need_dte field updated from the inner table t2. if the records are from "ui" table in the result, the need_dte is not being populated.
Is there any way using this join set up I need to get the need_dte for the result records from training_info table also if those records have a need_dte.
Thanks!
Is this what you want?
select t1.courseid, t1.coursename, t2.catid, t2.catname,
coalesce(ti.need_dte, t2.need_dte ) as need_dte
from t1 join
t2
on t1.courseid = t2.courseid and
t1.coursename = t2.coursename left outer join
training_info ti
on t1.courseid = ti.courseid and
t1.coursename = ti.coursename and
t2.need_dte = ti.need_dte;
I find your query with the nested subqueries, multiple levels of naming, and archaic join syntax to be difficult to read. I think the above is what you are looking for. It returns need_dte from training_info, if present, and then from t2.

Query using CASE, WHEN, THEN in postgresql not working

I have three tables, tbl_doctors_details, tbl_time and tbl_token.
I have to select the details from tbl_time or tbl_token. That is if for particular doctor in hospital have t_type is time then select from tbl_time else select from tbl_token.
For example, for doctor_id is 100 and hospital_id 1, the t_type is time. So for this user, details should select from tbl_time table.
Below is the sample structure and data of three tables:
How can I use CASE condition in query here?
I tried:
SELECT *
FROM
( SELECT * CASE WHEN t_type= 'time' FROM dbname.tbl_doctors_details t1 THEN
dbname.tbl_time t2
ELSE
dbname.tbl_token t2
WHERE t1.hospital_id=t2.hospital_id AND t1.doctor_id=t2.doctor_id);
I know the query is not working, but how can I make the query working?
You need to join both tables using two LEFT JOINs and then COALESCE to find the matching data:
SELECT t1.*,
colaesce(t_time.hospid, t_token.hospid),
colaesce(t_time.start, t_token.start)
FROM dbname.tbl_doctors_details t1
LEFT JOIN dbname.tbl_time t_time
ON t1.doctor_id=t_time.doctor_id
AND t1.t_type= 'time'
LEFT JOIN dbname.tbl_token t_token
ON t1.doctor_id=t_token.doctor_id
AND t1.t_type= 'token';
Use CASE WHEN in your SELECT and LEFT JOIN both tables. In both LEFT JOIN use the condition of t_type to join on the tables. In your SELECT you can now check whether table t1 or t2 was joined and select the preferred column. Here's a sample (the selected column is just a sample to illustrate):
SELECT CASE WHEN t1.id IS NULL THEN t2.id ELSE t1.id END AS joined_id
FROM tbl_doctors_details as tbl_base
LEFT JOIN tbl_time t1 ON t1.t_type = 'time' AND t1.doc_id = tbl_base.doc_id
LEFT JOIN tbl_token t2 ON t2.t_type = 'token' AND t2.doc_id = tbl_base.doc_id
Serious smell of doing homework for someone here.. Meh
SELECT
doctors.*
, CASE
WHEN doctors.type = 'time' THEN time.start
ELSE token.start
END AS start
FROM
doctors
LEFT OUTER JOIN time
ON time.doc_id = doctors.doc_id
AND time.hospital_id = doctors.hospital_id
AND doctors.t_type = 'time'
LEFT OUTER JOIN token
ON token.doc_id = doctors.doc_id
AND token.hospital_id = doctors.hospital_id
AND doctors.t_type = 'token'

Getting a ton of duplicates? Left Join incorrect?

Here is a sample of my query:
SELECT ...
TRIM(eml.fxeml1) as "Email Address"
FROM pfship
LEFT JOIN mstfxem fax
ON fax.fxco=pfship.cshco AND fax.fxdiv=pfship.cshdiv AND fax.fxsold=pfship.cshsld
AND fax.fxtype='C' AND TRIM(fax.fxfax1) <> '' AND fax.fxdept LIKE '*F%'
LEFT JOIN mstfxem eml
ON eml.fxco=pfship.cshco AND eml.fxdiv=pfship.cshdiv AND eml.fxsold=pfship.cshsld
AND eml.fxtype='C' AND TRIM(eml.fxeml1) <> '' AND eml.fxdept LIKE '*E%'
WHERE ((pfship.cshco || '/' || pfship.cshdiv) = ?)
AND (? = '*ALL' OR CAST(cshsld AS CHAR(15)) = ?)
AND ...
ORDER BY TRIM(cshnme)
This query should return 9 records. When I remove:
LEFT JOIN mstfxem fax
ON fax.fxco=pfship.cshco AND fax.fxdiv=pfship.cshdiv AND fax.fxsold=pfship.cshsld
AND fax.fxtype='C' AND TRIM(fax.fxfax1) <> '' AND fax.fxdept LIKE '*F%'
LEFT JOIN mstfxem eml
ON eml.fxco=pfship.cshco AND eml.fxdiv=pfship.cshdiv AND eml.fxsold=pfship.cshsld
AND eml.fxtype='C' AND TRIM(eml.fxeml1) <> '' AND eml.fxdept LIKE '*E%'
I get 9 records, but with it I get 360 records. What is wrong with my join?
Thanks
I think the problem is that 1 person can have many emails or faxes, how do I group the results into 1 string per record so I end up with only 9 records?
Nothing is wrong with your join, you have a one to many relationship between the tables.
Depending on what you need there are several techniques. First is the derived table. Write a query to pick out only one record from the one to many table (your requirements should specify which record to pick). Join to that instead. OR you may be able to put further conditions on the left join to get only one record. Some examples of these techniques:
select t1.field1, t2.email
from table1 t1
join (select myid, max(email) as email from table2 group by myid) t2
on t1.myid = t2.myid
Or
select t1.field1, t2.email
from table1 t1
Left join from table2 t2
on t1.myid = t2.myid and t2.active = 1
Or if you want all of the emails in a comma delimited list, that code is database specific and you would need to let us know which database backend you are using.