Use PROC SQL to select null when two conditions are met - sql

I am running a code where i am creating a table by taking all the columns from a table and then adding two columns from a second table. In the case when the two values coming from the second table are equal to 0 i need to set them to null. I can have other combinations such as FIELD1 = 0 and FIELD1 = 1 for example but not both equal to 0.
I am using PROC SQL like this:
PROC SQL;
CREATE TABLE TABLEA AS
SELECT A.*,
CASE
WHEN (B.FIELD1 NE 0 AND B.FIELD2 NE 0)
THEN B.FIELD1
ELSE .
END
AS FIELD1,
CASE
WHEN (B.FIELD2 NE 0 AND B.FIELD1 NE 0)
THEN B.FIELD2
ELSE .
END
AS FIELD2
FROM TABLE1 AS A
LEFT JOIN TABLE2 AS B ON A.ID = B.ID;
QUIT;
The code i am showing is not working, i still see a lot of records where FIELD1 = 0 and FIELD2 = 0 in the resulting table TABLEA.
What am i missing here?

Turns out i need to make sure that the variables don't already exist otherwise it will just keep the existing ones and cause this confusion.

Related

PROC SQL - Case when with multiple tables

I need to create a dataset (TABLE3) in order to check if some variables from other two tables are equals. If so, the code must return 0, otherwise 1. But, as I'm a new user of SAS and SQL I'm struggling to figure out how to do that.
I'm trying something like that but it's not working.
PROC SQL;
CREATE TABLE TABLE3 AS
SELECT A.*, B.*
CASE WHEN B.VARIABLE1 = A.VARIABLE2 THEN 0 ELSE 1 END AS VARIABLE_1_2,
CASE WHEN B.VARIABLE3 = A.VARIABLE4 THEN 0 ELSE 1 END AS VARIABLE_3_4
FROM TABLE1 AS A
LEFT JOIN TABLE2 AS B;
P.S.: Variables 1, 2, 3 and 4 are all character variables.
In addition to the tables relation you must add after the join, You miss a coma "," just before the first case.
For a JOIN condition to work, there must a ON clause
PROC SQL;
CREATE TABLE TABLE3 AS
SELECT A.*, B.*,
CASE WHEN B.VARIABLE1 = A.VARIABLE2 THEN 0 ELSE 1 END AS VARIABLE_1_2,
CASE WHEN B.VARIABLE3 = A.VARIABLE4 THEN 0 ELSE 1 END AS VARIABLE_3_4
FROM TABLE1 AS A LEFT JOIN TABLE2 AS B
**ON TABLE1.SOME_COLUMN_NAME = TABLE2.SOME_COLUMN_NAME**
;

SQL Conditional filter with different values

I have found lots of posts on coniditonal filtering in the where clause, but they all seem to be based off of using the same value, such as:
WHERE (o.OrderID = #orderid OR #orderid IS NULL)
I need to do something slightly different, I need to remove a filter and its value completely base on another value, so something like:
select *
from tableA
where 1 = 1
case when a = 1 then
and b in (select b from tableB)
else
-- do nothing
end
I know that the above is not allowed, and I am just writing as an example of what I am trying to do. does Anyone have any idea of a good way to do this? I know i could use if statements and duplicate the query, but it is a large one, and i am trying to avoid that.
Thanks
SELECT *
FROM tableA
WHERE a <> 1
OR (a = 1 AND EXISTS(SELECT b from TableB WHERE tableA.b = TableB.b))
You could also write this as:
SELECT tableA.*
FROM tableA
LEFT JOIN tableB
ON tableA.b = tableB.b
WHERE tableA.a <> 1
OR (tableA.a = 1 AND tableB.b IS NOT NULL)
"Correcting" your WHERE clause:
select *
from tableA
where 'T' = case
when a = 1 then case
when b in (select b from tableB) then 'T'
end
else 'T'
end;

calculate value based on 2 fields in SQL database

I can do this with linq easy but i got a situation where i have to create a stored procedure to return true or false based on 2 fields(minrange,maxrange) in table B. So, the goal is given an id from table A, i select the range value from table A and compare this value to the 2 ranges in table B. If the value is within range(minrange,maxrange) return true. Thanks.
I'm assuming you have a field that allows you to join records from Table A to Table B. I'll call it "CategoryID". Try this:
SELECT
CASE WHEN TableA.Value BETWEEN TableB.MinValue AND TableB.MaxValue
THEN 1 ELSE 0 END
FROM TableA
INNER JOIN TableB ON TableA.CategoryID = TableB.CategoryID
WHERE TableA.ID = "TheID"
Good luck!
-Michael
Without knowing specifics (as to foreign keys), this syntax should work.
SELECT
CAST((CASE
WHEN tableAValue < tableB.maxRange and tableAValue > tableB.minRange
THEN 1
ELSE
0
END) AS BIT)
FROM TableA
INNER JOIN TableB
ON TableA.ID = TableB.TableAID
WHERE TableA.ID = #yourID

SQL Statement Performance Issue on Informix

I have this Informix SQL statement which takes ages to run. Does anybody see any way to optimize it so it wouldn't take so long?
SELECT * FROM OriginalTable WHERE type = 'S' AND flag <> 'S' INTO TEMP TempTableA;
SELECT * FROM OriginalTable WHERE type = 'Z' AND flag <> 'S' INTO TEMP TempTableB;
UPDATE OriginalTable SET flag = 'D' WHERE Serialnumber in
(
select Serialnumber from TempTableA
WHERE NOT EXISTS(SELECT * FROM TempTableB
WHERE TempTableB.Col1 = TempTableA.Col1
AND TempTableB.Col2 = TempTableA.Col2)
)
I have in my OriginalTable around 300 million rows, TempTableA 93K rows, and TempTableB 58K rows.
Update OriginalTable
Set flag = 'D'
Where Type = 'S'
And Flag <> 'S'
And Not Exists (
Select 1
From OriginalTable As T1
Where T1.Type = 'Z'
And T1.flag <> 'S'
And T1.Col1 = OriginalTable.Col1
And T1.Col2 = OriginalTable.Col2
)
In a similar approach as #tombom stated. Pre-query only the columns you care about to keep the temp table smaller. If you are dealing with a table of 60 columns, you are filling a whole lot more than just 3-4 columns where your primary consideration are valid serial numbers. Pre-test the query to make sure it gives you the correct set you are expecting, then apply that to your SQL-update.
So here, the inner query are the ones you DO NOT WANT... Since you were comparing against only column 1 and column 2 from this table, that's all I'm pre-querying. I'm then doing a LEFT JOIN to this inner result set on COL1 and COL2. I know, you want to EXCLUDE THOSE FOUND IN THIS result set... That's why, in the OUTER WHERE clause, I've added "AND ExcludeThese.Col1 IS NULL". So, any instances from OT1 that never existed in the subquery are good to go (via left join), and those that WERE FOUND, WILL have a match on col1 and col2, but THOSE will be excluded via the "and" clause I've described.
SELECT OT1.SerialNumber
FROM OriginalTable OT1
LEFT JOIN ( select OT2.Col1,
OT2.Col2
FROM OriginalTable OT2
where OT2.type = 'Z'
AND OT2.flag <> 'S' ) ExcludeThese
ON OT1.Col1 = ExcludeThese.Col1
AND OT1.Col2 = ExcludeThese.Col2
WHERE OT1.type = 'S'
AND OT1.flag <> 'S'
AND ExcludeThese.Col1 IS NULL
ORDER BY
OT1.SerialNumber
INTO
TEMP TempTableA;
Again, test this query by itself to make sure you ARE getting the records you expect. To help clarify the records returned, change the above select to include more columns for a mental / sanity check, such as
SELECT OT1.SerialNumber,
OT1.Col1,
OT1.Col2,
ExcludeThese.Col1 JoinedCol1,
ExcludeThese.Col2 JoinedCol2
from <keep rest of query intact>
Now, you'll be able to see the serial number and instances of those columns that would or not be joined to the "excludeThese" resultset... Try again, but remove only the
"AND ExcludeThese.Col1 IS NULL" clause, and you'll see the other lines and WHY they are being excluded -- that is if you DID have any questions to the content.
Once you are satisfied with the pre-query... which will only return the single column of SerialNumber, that can be index/optimized since you are pulling into a temp table, build an index, then apply your update.
UPDATE OriginalTable
SET flag = 'D'
WHERE Serialnumber in ( select Serialnumber from TempTableA );
I was too lazy to test with test data, but maybe this can do?
SELECT col1, col2,
CASE WHEN type = 'S' THEN 1
ELSE WHEN type = 'Z' THEN 2 END AS filteredType
FROM OriginalTable WHERE (type = 'S' OR type = 'Z') AND flag <> 'S' INTO TempTable;
UPDATE OriginalTable SET flag = 'D' WHERE Serialnumber IN
(
SELECT t1.Serialnumber FROM TempTable t1
LEFT JOIN TempTable t2 ON (t1.col1 = t2.col2 AND t1.col2 = t2.col2)
WHERE t1.filteredType = 1
AND t2.filteredType = 2
AND t2.Serialnumber IS NULL
)
That way you can omit one loading into temp table. On the other hand there will be no index on the new column filteredType.
Also I have no idea of informix. Hope it helps anyway.

Update Field based on another table's values

Is there a more elegant way to write the following Microsoft SQL Server 2008 command?
UPDATE TableB
SET TableBField2=0
WHERE TableBID IN(
SELECT TableBID
FROM TableB
JOIN TableA on TableB.TableAID=TableA.TableAID
WHERE TableBField2 < 0
AND TableAField1 = 0
)
In plain speak, what I'm doing is updating a table based on the value of a field in a joined table. I wonder if my use of IN() is considered inefficient.
This should be more efficient:
UPDATE TableB b
SET TableBField2=0
WHERE exists (
SELECT 1
FROM TableA
WHERE b.TableAID=TableA.TableAID
AND b.TableBField2 < 0
AND TableAField1 = 0
)
You can try something like this
UPDATE TableB
SET Field2 = 0
FROM TableB b INNER JOIN
TableA a ON b.TableB.TableAID=a.TableAID
WHERE b.Field2 < 0
AND a.Field1 = 0