SQL Server Update sub query with formula not quite right - sql

I have a table (table1) of names and their frequencies
Name-----Frequency
Mike-------0.56
Fred-------0.30
Nancy------0.14
and a Cartesian product (table2) where the names are paired in two columns and a third column where I would like to sum the frequencies from table1 by matching the names in the first two columns back to table1.
Name1-------Name2------sum
Mike--------Fred
Mike--------Nancy
Fred--------Nancy
I want to update the sum column of table2 using the frequencies in table 1 with a subquery in the update for the matching names (Or so this is how I imagine I need to do it). If there is a better way please let me know.
I have:
UPDATE table2
SET sum = (SELECT dbo.table1.Frequency WHERE Name1 = dbo.table1.Name) +
(SELECT dbo.table1.Frequency WHERE Name2 = dbo.table1.Name)
FROM table1
I get a table full of NULLs instead of the frequency sums.
Am I going about this the right way? Am I totally missing how to do this and there is a better way to do it?

Try updating from a join like this:
update a
set a.sum=isnull(b.frequency,0)+isnull(c.frequency,0)
from table2 a
left join table1 b on a.name1=b.name
left join table1 c on a.name2=c.name

Your method is fine. If all names match:
UPDATE t2
SET sum = (SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name1 = f.Name) +
(SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name2 = f.Name)
FROM table2 t2;
If they don't, then use isnull() (or coalesce(), but isnull() is more efficient):
UPDATE t2
SET sum = isnull( (SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name1 = f.Name), 0) +
isnull( (SELECT f.frequency FROM dbo.table1.Frequency f WHERE t2.Name2 = f.Name), 0)
FROM table2 t2;

Related

Join table in oracle database

I have 2 tables that showing data Item master and BOM. I would like to join the tables between Item master as T1 and BOM as T2 and the additional table for table BOM as T3. Item master table containing ITM_CD, ITM_TYP (1,2,3,4) where each ITM_TYP represents a code for the first digit on ITM_CD. The thing that I want is like the picture below
CHILD_CD2 value replace to CHILD_CD1 value. So the data should be like this. What query should I fix ? I am very new using oracle query.
Here is mycode;
SELECT DISTINCT
T1.ITM_CD,
T2.C_ITM_CD AS CHILD_CD1,
T3.C_ITM_CD AS CHILD_CD2
FROM CM_HINMO_ALL T1
INNER JOIN (SELECT P_ITM_CD, C_ITM_CD, BOM_PTN FROM SM_BOM_ALL) T2
ON T1.ITM_CD = T2.P_ITM_CD
LEFT JOIN (SELECT P_ITM_CD, C_ITM_CD, BOM_PTN FROM SM_BOM_ALL) T3
ON T2.C_ITM_CD = t3.P_ITM_CD
WHERE 0=0
AND T2.BOM_PTN IN (1)
AND T1.ITM_TYP IN (1,2)
AND T1.ITM_CD = '110100370'
ORDER BY 2
Just use Case expression to replace the values.
SELECT ITM_CD, CASE WHEN CHILD_CD2 IS NULL THEN CHILD_CD2 ELSE CHILD_CD1 END AS CHILD_CD1
FROM TABLE1
If I understood, you want child_cd2 value should taken precedence over child_cd1 if available. If this assumption is right then we can use coalesce which returns the fist non null expression to achieve the same.
SELECT DISTINCT
T1.ITM_CD,
COALESCE(T3.C_ITM_CD,T2.C_ITM_CD) AS CHILD_CD1
FROM CM_HINMO_ALL T1
INNER JOIN SM_BOM_ALL T2
ON T1.ITM_CD = T2.P_ITM_CD
LEFT JOIN SM_BOM_ALL T3
ON T2.C_ITM_CD = t3.P_ITM_CD
WHERE T2.BOM_PTN IN (1)
AND T1.ITM_TYP IN (1,2)
AND T1.ITM_CD = '110100370'
ORDER BY 2

Postgresql Update using Inner Join set

I have two tables that they share two fields (myfield1, myfield2) and one of the two tables has 2 other fields of interest.
Here is what I want to do:
1. Inner Join the two tables
2. Update a column (field1) in Table2 with either fields (afield or anotherfield) from the other table depending on afield is null or not.
The code below runs fine but the targeted set field (field1) doesn't get updated with anything.
Update Table2
Set field1 = (
CASE
WHEN os.afield is not null
THEN (os.afield)
Else os.anotherfield
End
)
from Table1 os
inner join Table2 fd
ON fd.myfield1= os.myfield1
AND fd.myfield2 = os.myfield2;
Update Table2 fd
Set fd.field1 =
(select CASE WHEN os.afield is not null THEN (os.afield) Else os.anotherfield End
from Table1 os
where fd.myfield1= os.myfield1
AND fd.myfield2 = os.myfield2);
It's called a correlated subquery which is executed for each row in Table2. But you must be sure that subquery returns single or zero rows.
This query will update all rows in Table2 if you want to update only those rows which exist in Table1 you need a WHERE
Update Table2 fd
Set fd.field1 =
(select CASE WHEN os.afield is not null THEN (os.afield) Else os.anotherfield End
from Table1 os
where fd.myfield1= os.myfield1
AND fd.myfield2 = os.myfield2)
where exists (
select 1 from Table1 os
where fd.myfield1= os.myfield1
AND fd.myfield2 = os.myfield2);

Select records from one table based on records from another table

this is a simplified version of a problem I'm having,
I have two tables:
Table1 has two columns (Stuff, YesNo) and
Table2 has one column (Stuff)
The records in the YesNo Column will either be 1 or 0
How could I select records in Table2 where the records in Table1.YesNo = 1
Many Thanks
SELECT Table2.*
FROM Table2
INNER JOIN Table1 ON Table1.Stuff = Table2.Stuff
WHERE Table1.YesNo = 1
If I understand you correctly, this would be your solution:
Select Stuff From Table2
Where Exists (
Select 'Y'
From Table1
Where Table1.Stuff = Table2.Stuff
And YesNo = 1
)
As I believe you'll need data from both tables and you may want to render fields unique to each table This seems like a likely response. However, as I don't believe STUFF accurately represents the relationship... you'll need to quantify/adjust the on a.stuff = b.stuff so that the join includes all necessary fields.
SELECT A.Stuff, B.Stuff, B.YesNo
FROM table1 B
INNER JOIN table2 A
on A.Stuff = B.Stuff
WHERE B.YesNo = 1
SELECT T2.*
FROM TABLE1 T1
JOIN TABLE2 T2
ON T1.Stuff = T2.Stuff
WHERE T1.YesNo = 1

Is possible have different conditions for each row in a query?

How I can select a set of rows where each row match a different condition?
Example:
Supposing I have a table with a column called name, I want the result ONLY IF the first row name matches 'A', the second row name matches 'B' and the third row name matches 'C'.
Edit:
I want to do this to work without a fixed size, but in a way I can define the sequence like R,X,V,P,T and it matches the sequence, each one in a row, but in the order.
you can, but probably not in a way you would want:
if your table has a numeric id field, that is incremented with each row, you can self join that table 3 times (lets say as "a", "b" and "c") and use the join condition a.id + 1 = b.id and b.id + 1 = c.id and put you filter in a where clause like: a.name = 'A' AND b.name = 'B' AND c.name = 'C'
but don't expect performance ...
Assuming that You know how to provide a row number to your rows (ROW_NUMBER() in SQL Server, for instance), You can create a lookup (match) table and join on it. See below for explanation:
LookupTable:
RowNum Value
1 A
2 B
3 C
Your SourceTable source table (assuming You already added RowNum to it-in case You didn't, just introduce subquery for it (or CTE for SQL Server 2005 or newer):
RowNum Name
-----------
1 A
2 B
3 C
4 D
Now You need to inner join LookupTable with your SourceTable on LookupTable.RowNum = SourceTable.RowNum AND LookupTable.Name = SourceTable.Name. Then do a left join of this result with LookupTable on RowNum only. If there is LookupTable.RowNum IS NULL in final result then You know that there is no complete match on at least one row.
Here is code for joins:
SELECT T.*, LT2.RowNum AS Matched
FROM LookupTable LT2
LEFT JOIN
(
SELECT ST.*
FROM SourceTable ST
INNER JOIN LookupTable LT ON LT.RowNum = ST.RowNum AND LT.Name = ST.Name
) T
ON LT2.RowNum = T.RowNum
Result set of above query will contain rows with Matched IS NULL if row is not matching condition from LookupTable table.
I suppose you could do a sub query for each row, but it wouldn't perform well or scale well at all and would be hard to maintain.
This may be close to what your after... but I need to know where you're getting your values for A, B, C etc...
Select [insert your fields here]
FROM
(Select T1.Name, T1.Age, RowNum as t1RowNum from T T1 order by name) T1O
Full Outer JOIN
(Select T2.Name, T2.Age, RowNum as T2rowNum From T T2 order By name) T2O
ON T1O.T1RowNum+1 = T2O.T2RowNum

How do I compare 2 rows from the same table (SQL Server)?

I need to create a background job that processes a table looking for rows matching on a particular id with different statuses. It will store the row data in a string to compare the data against a row with a matching id.
I know the syntax to get the row data, but I have never tried comparing 2 rows from the same table before. How is it done? Would I need to use variables to store the data from each? Or some other way?
(Using SQL Server 2008)
You can join a table to itself as many times as you require, it is called a self join.
An alias is assigned to each instance of the table (as in the example below) to differentiate one from another.
SELECT a.SelfJoinTableID
FROM dbo.SelfJoinTable a
INNER JOIN dbo.SelfJoinTable b
ON a.SelfJoinTableID = b.SelfJoinTableID
INNER JOIN dbo.SelfJoinTable c
ON a.SelfJoinTableID = c.SelfJoinTableID
WHERE a.Status = 'Status to filter a'
AND b.Status = 'Status to filter b'
AND c.Status = 'Status to filter c'
OK, after 2 years it's finally time to correct the syntax:
SELECT t1.value, t2.value
FROM MyTable t1
JOIN MyTable t2
ON t1.id = t2.id
WHERE t1.id = #id
AND t1.status = #status1
AND t2.status = #status2
Some people find the following alternative syntax easier to see what is going on:
select t1.value,t2.value
from MyTable t1
inner join MyTable t2 on
t1.id = t2.id
where t1.id = #id
SELECT COUNT(*) FROM (SELECT * FROM tbl WHERE id=1 UNION SELECT * FROM tbl WHERE id=2) a
If you got two rows, they different, if one - the same.
SELECT * FROM A AS b INNER JOIN A AS c ON b.a = c.a
WHERE b.a = 'some column value'
I had a situation where I needed to compare each row of a table with the next row to it, (next here is relative to my problem specification) in the example next row is specified using the order by clause inside the row_number() function.
so I wrote this:
DECLARE #T TABLE (col1 nvarchar(50));
insert into #T VALUES ('A'),('B'),('C'),('D'),('E')
select I1.col1 Instance_One_Col, I2.col1 Instance_Two_Col from (
select col1,row_number() over (order by col1) as row_num
FROM #T
) AS I1
left join (
select col1,row_number() over (order by col1) as row_num
FROM #T
) AS I2 on I1.row_num = I2.row_num - 1
after that I can compare each row to the next one as I need