PROC SQL - Case when with multiple tables - sql

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**
;

Related

Use PROC SQL to select null when two conditions are met

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.

Conditional join in SQL depending on a column value

I'm trying to do a join on a SAS table using PROC-SQL. Depending on the value of one variable in table A I need to join using a column, otherwise I need to use another column.
proc sql;
create table test
as select
A.*,
A.PPNG_RVNE * B.perc_ress as variable1,
A.P_RVNE * B.perc_ress as variable2
from tableA as A
left join tableB as B
on case when A.cod_cia = 1 then A.cod_cia=B.cod_cia and A.cod_agrup_produto=B.cod_agrup_produto
else A.cod_cia=B.cod_cia and A.projeto=B.projeto;
I need to join just to create variable1 and variable2. I don't want to select any variable from table B.
My cod doesn't run. SAS gives me an error message saying that it is expecting an `end.
Does anyone know how to conditional join depending on columns?
Don't use case. Just express the logic booleanly"
proc sql;
create table test as
select A.*, A.PPNG_RVNE * B.perc_ress as variable1, A.P_RVNE * B.perc_ress as variable2
from tableA A left join
tableB B
on A.cod_cia = B.cod_cia and
(A.cod_cia = 1 and A.cod_agrup_produto = B.cod_agrup_produto) or
(A.cod_cia <> 1 and A.projeto = B.projeto);
Note: This uses <> 1. If cod_cia could be NULL you need to take that into account. Also note that this factors out the first condition.
Not a PROC-SQL user so apologies if this is wrong, but based on this question a case statement needs the format:
CASE
WHEN ... THEN ...
WHEN ... THEN ...
ELSE ...
END
So have you tried:
proc sql;
create table test
as select
A.*,
A.PPNG_RVNE * B.perc_ress as variable1,
A.P_RVNE * B.perc_ress as variable2
from tableA as A
left join tableB as B
on case when A.cod_cia = 1 then A.cod_cia=B.cod_cia and A.cod_agrup_produto=B.cod_agrup_produto
else A.cod_cia=B.cod_cia and A.projeto=B.projeto
end;
I would use two joins and a coalesce statement:
proc sql;
create table test
as select
A.*,
A.PPNG_RVNE * coalesce(B1.perc_ress,B2.perc_ress) as variable1,
A.P_RVNE * coalesce(B1.perc_ress,B2.perc_ress) as variable2
from tableA as A
left join tableB as B1
on A.cod_cia = 1 and A.cod_cia=B1.cod_cia and A.cod_agrup_produto=B1.cod_agrup_produto
left join tableB as B2
on A.cod_cia=B2.cod_cia and A.projeto=B2.projeto;
you could add A.cod_cia ne 1 in the second join, but it's not necessary unless.

SQL Server--Is it possible to work around using a temporary table for a query that filters based on an alias case column?

I am trying to alter a base query that selects data from several joined tables, and filters out rows based on the CASE WHEN below. The result set is to be returned as follows:
If all of the rows return 0 in the CASE column, return one line with '0' in the OVERDUE column (the "return one line" portion is taken care of by DISTINCT.)
If any of the rows return 1 for the CASE column, return one line with '1' in the OVERDUE column.
The base is as follows:
SELECT DISTINCT t1.*,
CASE WHEN t3.MTemp > t3.MTempLimit
then 1
when t3.TotHours > t3.THoursLimit
then 1
else 0
end [Overdue]
from table_1 t1
LEFT JOIN table_2 t2 on t1.ResNo = t2.ResNo and t1.PCode = t2.PCode
LEFT JOIN table_3 t3 on t2.RepJobNo = t3.RepJobNo
LEFT JOIN table_4 t4 on t4.TypeID = t2.RepType
WHERE t2.RepStat = 1
The catch is, I've already created a working version of this by using a temp table and doing a IF EXISTS/ELSE query on the temp table's OVERDUE column. However, I've been informed that this solution may not be useable (due to having to go through certain front-end software).
Is it possible to do a workaround for this that does not involve using a temporary table? I've been making attempts at using both a derived table and CTEs, neither of which have yielded anything usable, due to the fact that one cannot use IF/ELSE clauses after those (which was what I was counting on).
I'm still getting the hang of T-SQL, so any help would be greatly appreciated.
Sounds like a simple ROW_NUMBER() and a couple of CTEs will work:
;WITH RS1 as (
SELECT t1.*,
CASE WHEN t3.MTemp > t3.MTempLimit
then 1
when t3.TotHours > t3.THoursLimit
then 1
else 0
end [Overdue]
from table_1 t1
LEFT JOIN table_2 t2 on t1.ResNo = t2.ResNo and t1.PCode = t2.PCode
LEFT JOIN table_3 t3 on t2.RepJobNo = t3.RepJobNo
LEFT JOIN table_4 t4 on t4.TypeID = t2.RepType
WHERE t2.RepStat = 1
), RS2 as (
select *,ROW_NUMBER() OVER (ORDER BY Overdue DESC) rn
from RS1
)
select * from RS2 where rn = 1
(There's no need for a DISTINCT now that we're only returning one row)
In general any temporary table referenced in another query can simply be substituted for as follow, so that this:
insert #temp
select -- definition of temptable
;
select ...
from #temp
join ...
becomes
select
from (
-- definition of temptable
) temp
join ...

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