SqlServer - search if a list of values is fully contained on table - sql

I have a sql table and a list of values to search.
if at least all the elements of the table are contained in the list, then I must return the Ticket Id (it means that I will update this record). Otherwise, I will return null (it means that it will be a new registration).
For example
Use cases:
If I search for this elements: C1, C3, C6, it will be an update and I will get ticketid 1
If I search for this elements: C8, C3, C6, C10, it will be a create and I will get null as return value
A list of values is a Predefined-Type with a column, in this case, #ElementsToSearch with a column Value
SELECT T.Id
FROM
Ticket t
INNER JOIN
TicketValue TL ON TL.TicketId = T.Id
LEFT OUTER JOIN
#ElementsToSearch ES ON ES.Value = TL.Value
WHERE
ES.Value is null
thank you

Whatever you want to return just interchange null and 1
declare #ElementsToSearch as Table(value varchar(10))
insert into #ElementsToSearch values('C1'),('C2'),('C3')
SELECT
CASE WHEN (COUNT(CASE WHEN ES.value IS NULL then 1 end)>0) then NULL else T.id end as output
FROM
Ticket t
INNER JOIN
TicketValue TL ON TL.TicketId = T.Id
LEFT OUTER JOIN
#ElementsToSearch ES ON ES.Value = TL.Value
group by T.id

Related

Filter a join based on multiple rows

I'm trying to write a query that filters a join based on several rows in another table. Hard to put it into words, so I'll provide a cut-back simple example.
Parent
Child
P1
C1
P1
C2
P1
C3
P2
C1
P2
C2
P2
C4
P3
C1
P3
C3
P3
C5
Essentially all rows are stored in the same table, however there is a ParentID allowing one item to link to another (parent) row.
The stored procedure is taking a comma delimited list of "child" codes, and based on whatever is in this list, I need to provide a list of potential siblings.
For example, if the comma delimited list was empty, the returned rows should be C1, C2, C3, C4, C5. If the list is "C2", the returned rows would be C1, C3, C4, and if the list is 'C1, C2', then the only returned row would be c3, c4.
Sample query:
SELECT [S].[ID]
FROM utItem [P]
INNER JOIN utItem [C]
ON [P].[ID] = [C].[ParentID]
INNER JOIN
(
-- Encapsulated to simplify sample.
SELECT [ID]
FROM udfListToRows( #ChildList )
GROUP BY
[ID]
) [DT]
ON [DT].[ID] = [C].[ID]
/*
In the event where I passed in "C2", this would work, it would return C1, C3, C4.
However this falls apart the moment there is more than 1 value in #ChildList. If I pass in "C2, C3", it would return siblings for either. But I only want siblings of BOTH.
**/
INNER JOIN [utItem] [S]
ON [C].[ParentID] = [S].[ParentID]
AND [C].[ID] <> [S].[ID]
WHERE
#ChildList IS NOT NULL
GROUP BY
[S].[ID]
UNION ALL
-- In the event that no #ChildList values are provided, return a full list of possible children (e.g. 1,2,3,4,5).
SELECT [C].[ID]
FROM [utItem] [P]
INNER JOIN [utItem] [C]
ON [P].[ID] = [C].[ParentID]
WHERE
#ChildList IS NULL
GROUP BY
[C].[ID]
Firstly, you can split your data into a table variable for ease of use
DECLARE #input TABLE (NodeId varchar(2));
INSERT #input (NodeId)
SELECT [ID]
FROM udfListToRows( #ChildList ); -- or STRING_SPLIT or whatever
Assuming you already had your data in a proper table variable (rather than a comma-separated list) you can do this
DECLARE #totalCount int = (SELECT COUNT(*) FROM #input);
SELECT DISTINCT
t.Child
FROM (
SELECT
t.Parent,
t.Child,
i.NodeId,
COUNT(i.NodeId) OVER (PARTITION BY t.Parent) matches
FROM YourTable t
LEFT JOIN #input i ON i.NodeId = t.Child
) t
WHERE t.matches = #totalCount
AND t.NodeId IS NULL;
db<>fiddle
This is a kind of relational division
Left-join the input to the main table
Using a window function, calculate how many matches you get per Parent
There must be at least as many matches as there are inputs
We take the distinct Child, excluding the original inputs

Select rows having value combination listed in another table

I have tables:
Result containing 5 columns: result_id, num_1, num_2, num_3, num_4
Ref containing 4 columns: num_1, num_2, num_3, num_4
Columns num contain random int in range of 1-9
Aim of exercise is to display all result_id from Result table which have num values combination present in Ref table and to display result_id which have not met combination criteria.
I've been trying left joining ref to result, but unfortunately no success. Could you please share some light how to deal with it?
If you want the result_id for which combination exists in the ref table then use following JOIN query:
select distinct r.result_id
from results r
join ref on r.num_1 = ref.num_1 and r.num_2 = ref.num_2
and r.num_3 = ref.num_3 and r.num_4 = ref.num_4
If you want the result_id for which combination do not exists in REF table then use the LEFT JOIN as follows:
select r.result_id
from results r
left join ref on r.num_1 = ref.num_1 and r.num_2 = ref.num_2
and r.num_3 = ref.num_3 and r.num_4 = ref.num_4
where ref.num_1 is null -- or use PK / Not nullable column of REF table here
Assuming you want the columns to "line up" and you want to add a flag to the result_id in the first table, then use exists:
select t1.*,
(case when exists (select 1
from table2 t2
where t2.n1 = t1.n1 and t2.n2 = t1.n2 and t2.n3 = t1.n3 and t2.n4
)
then 'present' else 'not present'
end) as flag
from t2;

Translation of a character to another SQL Server

I want to translate a character from A - B but also in the same query I want to translate B - C if is found on a list. Let's say we have word "Apple" that gets translated to "Orange" but "Orange" it is also on the list and it gets translated to "Coconut", so the final result would be "Coconut". Is this possible ?. I do not want to use a cursor but i just can't find the answer..
update tableA
set Value = b.TargetValue
from tableA a
join
tableB b on b.SourceValue = a.Value
from my TableA i have let's say a list of fruits for this example i just have the fruit "Apple" on tableA but in tableB i have a translation for that word to "Orange", but also in the same tableB i have a translation for "Orange" to "Coconut" so i would expect to have as final result "Coconut". Does that help? it's my first time sorry if i didn't explain well.
EDIT
I have created a function for this. Hope it helps someone else with the same problem.
CREATE FUNCTION [dbo].[FunctionName]
(
#sourceValue varchar(11)
)
RETURNS varchar(11)
AS
BEGIN
declare #targetId varchar(11) = (select TargetID from tableWithValues where
SourceID = #sourceValue)
if #targetId is not null and #targetId <> #sourceValue
begin
set #targetId = dbo.FunctionName(#targetId)
end
else
begin
return #sourceValue
end
return #targetId
end
I would suggest you get a final dataset by joining both fruit tables, so when you get your final fruit just join that dataset(cte or temp table) with the table you want to update.
Hope this approach helps you solve the problem.
I don't think that there is general solution for this, but there is a work-around if there are reasonable limits to the number of substitutions.
For example, the A => B => C you describe has two levels of substitution. If the max number of levels is e.g. 5 you can code like this:
update tableA
set Value = case when b5.TargetValue is not null then b5.targetValue
else when b4.TargetValue is not null then b4.TargetValue
else when b3.TargetValue is not null then b3.TargetValue
else when b2.TargetValue is not null then b2.TargetValue
else when b1.TargetValue is not null then b1.TargetValue
else b0.TargetValue end case
from tableA a
join
tableB b0 on b0.SourceValue = a.Value
left outer join tableB b1 -- outer join for no sub
on b1.SourceValue = b0.TargetValue
left outer join tableB b1
on b2.SourceValue = b1.TargetValue
left outer join tableB b1
on b3.SourceValue = b2.TargetValue
left outer join tableB b1
on b4.SourceValue = b3.TargetValue
left outer join tableB b1
on b5.SourceValue = b4.TargetValue
Here, 5 levels are supported: A =>B =>C =>D =>E =>F. If you have a situation where 6 levels are needed (e.g F => G) then it won't happen, and the result will be F.
Note that the order of the when bx.TargetValue is not null statements is important.

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.

Link tables based on column value

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