Link tables based on column value - sql

Is it possible to pull values from 2 different tables based on the value of a column? For example, I have a table with a boolean column that either returns 0 or 1 depending on what the end user selects in our program. 0 means that I should pull in the default values. 1 means to use the user's data.
If my table Table1 looked like this:
Case ID Boolean
====================
1 0
2 1
3 1
4 0
5 0
Then I would need to pull Case IDs 1,4,and 5's corresponding data from table Default and Case IDs 3 and 4's corresponding data from table UserDef. Then I would have to take these values, combine them, and reorder them by Case ID so I can preserve the order in the resulting table.
I am fairly inexperienced with SQL but I am trying to learn. Any help or suggestions are greatly appreciated. Thank you in advance for your help.

Something like this:
SELECT
t1.CaseID
,CASE WHEN t1.Boolean = 1 THEN dt.Col1 ELSE ut.Col1 END AS Col1
,CASE WHEN t1.Boolean = 1 THEN dt.Col2 ELSE ut.Col2 END AS Col2
FROM Table1 t1
LEFT JOIN DefaultTable dt ON dt.CaseID = t1.CaseID
LEFT JOIN UserDefTable ut ON ut.CaseID = t1.CaseID
ORDER BY t1.CaseID
You join on both tables and then use CASE in SELECT to choose from which one to display data.
Option B:
WITH CTE_Combo AS
(
SELECT 0 as Boolean, * FROM Default --replace * with needed columns
UNION ALL
SELECT 1 AS Boolean, * FROM UserDef --replace * with needed columns
)
SELECT * FROM Table1 t
LEFT JOIN CTE_Combo c ON t.CaseID = c.CaseID AND t.Boolean = c.Boolean
ORDER BY t.CaseID
This might be even simpler - using CTE make a union of both tables adding artificial column, and then join CTE and your Table using both ID and flag column.

SELECT t1.CaseID,
ISNULL(td.data, tu.data) userData -- pick data from table_default
-- if not null else from table_user
FROM table1 t1
LEFT JOIN table_default td ON t1.CaseID = td.CaseID -- left join with table_default
AND t1.Boolean = 0 -- when boolean = 0
LEFT JOIN table_user tu ON t1.CaseID = tu.CaseID -- left join with table_user
AND t1.Boolean = 1 -- when boolean = 1
ORDER BY t1.CaseID

Related

SQL statement return matching records from join and null records from join

I have a db with records like the following structure in the table;
id,msg,date,fid
19 ,"start","2012-02",NULL
20 ,"end","2012-03",19
21 , "start",2012-04,NULL
I have and entire db set up like this where the fid in some cases matches the id of another record. Id like to return all records that have matching start and end dates and just the start date if it doesn't have a corresponding end date fid like below:
19 ,"start","2012-02","end","2012-03"
21 , "start,"2012-04,"",NULL
I think you want a left join:
select t.fid, t.date as start_date, tf.date as end_date
from t left join
t tf
on tf.id = t.fid
where t.msg = 'start'
This assumes that there are only two types of records and fid is always non-NULL for 'end' records.
You just need a LEFT OUTER JOIN to your table. You can use an alias to refer to each instance:
SELECT startdt.id, startdt.msg, startdt.date, enddt.msg, enddt.date
FROM yourtable as startdt
LEFT OUTER JOIN yourtable as enddt
ON startdt.fid = enddt.id
AND enddt.msg = 'end'
WHERE startdt.msg = 'start'

Adding CASE expression in the correct spot?

I want to change this query:
select
t.AccountA
,t.AccountB
,t.totalNumber
,a.Category
from TableA t
left join Accounts a
on t.ActNum = a.ActNum
left join
(select distinct
s.col1
from (
select ....
from Table
group by...
) st
left join (select S....
group by..
) g on...
left join (select... on ...
) t on ...
where...
)
so that c.AccountB displays "X" if it was a "Y". So I want to do something like
CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE 'c.AccountB END
Except I'm having a problem where some data (a.Category) is coming from the table a, and table a doesn't have a record in it equal to "Y", so the join doesn't get the category data from a. That field is therefore blank. I'm trying to avoid adding it to that table and would rather change the query. How can I do this? What I think would work is:
select
t.AccountA
,t.AccountB
,t.totalNumber
,a.Category
from TableA t
left join ****** (Select CASE WHEN t.AccountB = 'Y' THEN 'X' ELSE 't.AccountB END Accounts a)
on t.ActNum = a.ActNum
left join
(select distinct
col1
from (
select ....
from Table
group by...
) sta
left join (select S....
group by..
) g on...
left join (select... on ...
) t on ...
where...
)
Where I put the CASE expression in the 7th line here by the asterisks ***
Will this return exactly the same records? This is a really long running query and difficult to test so I'm trying to run it as few times as possible, would like some input to help me so this doesn't turn into a 6 hour project.
EDIT: I had a typo, the first columns selected were supposed to reference the first table - I changed it (table "t")
First, this might be as simple as getting rid of the single quote before c.AccountB CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END Otherwise I'm not quite sure I understand what you want but I'll try:
If you just want to select then:
select
c.AccountA
,CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END AccountB
,totalNumber
,a.Category
from TableA t
left join Accounts a
on t.ActNum = a.ActNum
left join
...
If instead you want to use this as part of a join you'll have to use it in your join. Since you don't show how "c" is joined, nor how "c" and "a" are related I will try to give an example:
select
c.AccountA
,CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END AccountB
,totalNumber
,a.Category
from CheckRegister c
left join Accounts a
on a.ActNum = c.AccountA
left join Accounts b
on b.ActNum = CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END

How to write a query to get data count with combination of codision

I have two tables named [DrugPrescriptionEdition] and [PrescriptionDoseDetail] and now, I join that two tables using the below query and taking a result set.
select * from DrugPrescription dp where id in(
SELECT distinct dpe.template
FROM [DrugPrescriptionEdition] dpe
join PrescriptionDoseDetail pdd on pdd.prescription = dpe.id
where doseEnd_endDate is NULL and doseEnd_doseEndType =1
)
but now I want to take records only contain, (1,2) combination of 'datasource' column and prescription.id should be same.
Example : like records { prescriptionID =4 and there contain ,(1,2) }. I will not consider, only 1 ,or 2 contain records.
Need some expert help to adding this conditions to my above query and modify it .
Expected result : I need to filter out , above query result using this, new condition too.
Let me assume your records are in a single table. Here is one method:
select t.*
from t
where (t.dataSource = 1 and
exists (select 1
from t t2
where t2. prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
) or
(t.dataSource = 2 and
exists (select 1
from t t2
where t2.prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
);
It is unclear if any other data sources are allowed. If they are not, then add:
and
not exists (select 1
from t t3
where t3.prescriptionid = t.prescriptionid and
t3.dataSource not in (1, 2)
)

Performance Issue in Left outer join Sql server

In my project I need find difference task based on old and new revision in the same table.
id | task | latest_Rev
1 A N
1 B N
2 C Y
2 A Y
2 B Y
Expected Result:
id | task | latest_Rev
2 C Y
So I tried following query
Select new.*
from Rev_tmp nw with (nolock)
left outer
join rev_tmp old with (nolock)
on nw.id -1 = old.id
and nw.task = old.task
and nw.latest_rev = 'y'
where old.task is null
when my table have more than 20k records this query takes more time?
How to reduce the time?
In my company don't allow to use subquery
Use LAG function to remove the self join
SELECT *
FROM (SELECT *,
CASE WHEN latest_Rev = 'y' THEN Lag(latest_Rev) OVER(partition BY task ORDER BY id) ELSE NULL END AS prev_rev
FROM Rev_tmp) a
WHERE prev_rev IS NULL
My answer assumes
You can't change the indexes
You can't use subqueries
All fields are indexed separately
If you look at the query, the only value that really reduces the resultset is latest_rev='Y'. If you were to eliminate that condition, you'd definitely get a table scan. So we want that condition to be evaluated using an index. Unfortunately a field that just values 'Y' and 'N' is likely to be ignored because it will have terrible selectivity. You might get better performance if you coax SQL Server into using it anyway. If the index on latest_rev is called idx_latest_rev then try this:
Set transaction isolated level read uncommitted
Select new.*
from Rev_tmp nw with (index(idx_latest_rev))
left outer
join rev_tmp old
on nw.id -1 = old.id
and nw.task = old.task
where old.task is null
and nw.latest_rev = 'y'
latest_Rev should be a Bit type (boolean equivalent), i better for performance (Detail here)
May be can you add index on id, task
, latest_Rev columns
You can try this query (replace left outer by not exists)
Select *
from Rev_tmp nw
where nw.latest_rev = 'y' and not exists
(
select * from rev_tmp old
where nw.id -1 = old.id and nw.task = old.task
)

SQL: Want to alter the conditions on a join depending on values in table

I have a table called Member_Id which has a column in it called Member_ID_Type. The select statement below returns the value of another column, id_value from the same table. The join on the tables in the select statement is on the universal id column. There may be several entries in that table with this same universal id.
I want to adjust the select statement so that it will return the id_values for entries that have member_id_type equal to '7'. However if this is null then I want to return records that have member_id_type equal to '1'
So previously I had a condition on the join (commented out below) but that just returned records that had member_id_type equal to '7' and otherwise returned null.
I think I may have to use a case statement here but I'm not 100% sure how to use it in this scenario
SELECT TOP 1 cm.Contact_Relation_Gid,
mc.Universal_ID,
mi.ID_Value,
cm.First_Name,
cm.Last_Name,
cm.Middle_Name,
cm.Name_Suffix,
cm.Email_Address,
cm.Disability_Type_PKID,
cm.Race_Type_PKID,
cm.Citizenship_Type_PKID,
cm.Marital_Status_Type_PKID,
cm.Actual_SSN,
cm.Birth_Date,
cm.Gender,
mc.Person_Code,
mc.Relationship_Code,
mc.Member_Coverage_PKID,
sc.Subscriber_Coverage_PKID,
FROM Contact_Member cm (NOLOCK)
INNER JOIN Member_Coverage mc (NOLOCK)
ON cm.contact_relation_gid = mc.contact_relation_gid
AND mc.Record_Status = 'A'
INNER JOIN Subscriber_Coverage sc (NOLOCK)
ON mc.Subscriber_Coverage_PKID = sc.Subscriber_Coverage_PKID
AND mc.Record_Status = 'A'
LEFT outer JOIN Member_ID mi ON mi.Universal_ID = cm.Contact_Gid
--AND mi.Member_ID_Type_PKID='7'
WHERE cm.Contact_Relation_Gid = #Contact_Relation_Gid
AND cm.Record_Status = 'A'
Join them both, and use one if the other is not present:
select bt.name
, coalesce(eav1.value, eav2.value) as Value1OrValue2
from BaseTable bt
left join EavTable eav1
on eav1.id = bt.id
and eav1.type = 1
left join EavTable eav2
on eav2.id = bt.id
and eav2.type = 2
This query assumes that there is never more than one record with the same ID and Type.