Conditional view in oracle - sql

Below is the table from which I need to create conditionalize view.
and I am getting one flag from different table. So based on the flag values i.e. if flag=1 then I need to display actual column values from table, and if flag=0 then show all column values as null values.
I know we can handle it using CASE statement but here, in may case column count is very big so need to handle it in better way.

You could try using a CASE expression along with REGEXP_REPLACE to mask the value column:
SELECT ID,
CASE WHEN flag = 1 THEN Value ELSE REGEXP_REPLACE(Value, '.', '*') END AS Value
FROM yourTable;

You can use left join:
select t.*
from (select 1 as flag from dual) x left join
t
on x.flag = :flag;
If :flag = 1, then all columns will be shown. If :flag is anything else, then all values will be NULL.
If you actually want to show the ids, it is a little more complicated:
select i.*, t.*
from (select 1 as flag from dual) x left join
(select id, . . . -- columns you want to keep
from t
) i left join
t
on x.flag = :flag and t.id = i.id;
You will probably need to list out the columns with the NULL values.

Related

SQL Select row depending on values in different columns

I've already found so many answers here but now I can't seem to find any to my specific problem.
I can't figure out how to select a value from a row depending on the value in different columns
with the below table, I want to achieve the following results.
in case the value in column stdvpuni = 1 then return values / contents from this row for the article (column art).
in case the value in column stdvpuni = 0 then return values / contents from the row where STDUNIABG = 1 for this article (column art).
You seem to want one row part art, based on the content of other rows. That suggests using row_number():
select t.*
from (select t.*,
row_number() over (partition by art order by stdvpuni desc, STDUNIABG desc) as seqnum
from t
) t
where seqnum = 1;
You don't specify what to do if neither column is 1. You might want a where clause (where 1 in (stdvpuni, STDUNIABG)) or another condition in the order by.
I do not know what values / contents is, but I suppose that's easy for you to figure out. So, I will focus on the way to select this:
SELECT
CASE
WHEN current.stdvpuni = 1 THEN 'values / contents of current row'
ELSE 'values / contents of other row'
END
FROM yourtable current
JOIN yourtable other
ON other.stdvpuni = 1;
Use your conditions with NOT EXISTS in the WHERE clause:
SELECT t1.*
FROM tablename t1
WHERE t1.STDVPUNI = 1
OR (
t1.STDVPUNI = 0 AND t1.STDUNIABG = 1
AND NOT EXISTS (SELECT 1 FROM tablename t2 WHERE t2.ART = t1.ART AND t2.STDVPUNI = 1)
);

Not a group expression: troubleshooting an Oracle query

Oracle query
I have a column value with hardcoded value 'N/A' and other char values as well. I need to write a select query to get the min of this column grouping the other set of columns.. but the challenge is i need to replace the hard coded value of 'N/A' with another character 'Abc' along with min function
Option 1: nvl won't work as the value is hardcoded
Option 2: decode in the select statement along with min clause in the decode list, and group by clause with the other columns used in the select list
However, getting an error
ORA-00979 : not a group expression.
Example :
Select a, b, decode(z,'N/A','abc',min(z))
From table 1, table 2
Where table 1.p=table2.q
Group by a,b
Having c.table1 >= table2.d
You should be using DECODE inside the MIN function, not the other way around. But, I would probably just use a single CASE expression here:
SELECT
a,
b,
MIN(CASE WHEN z = 'N/A' THEN 'abc' ELSE z END) AS min_value
FROM table1 t1
INNER JOIN table2 t2
ON t1.p = t2.q
GROUP BY
a,
b;
The above CASE expression is just taking the minimum value of z for each group, with the only difference between MIN(z) being that should the value be N/A, it would be treated as abc.

Compare each row values in second table in SQL Server?

I have a scenario where I have to search value of column 1 in first table to see whether it matches some value in another table.
This should continue in a loop until the last row on first table has been compared.
No loops needed. You can do this easily as a set based operation using exists()
select *
from FirstTable
where exists (
select 1
from SecondTable
where FirstTable.Column1 = SecondTable.Column1
);
To find the opposite, where the row in the first table does not have a match based on Column1, you can use not exists()
select *
from FirstTable
where not exists (
select 1
from SecondTable
where FirstTable.Column1 = SecondTable.Column1
);
If you want to identify which rows have a match and don't you can use:
select FirstTable.*
, MatchFound = case when x.Column1 is null then 'No' else 'Yes' end
, x.Column1
from FirstTable
outer apply (
select top 1
*
from SecondTable
where FirstTable.Column1 = SecondTable.Column1
) as x

SQL: Difference between rows

I am trying to find the difference between two numbers corresponding to the same ID, but with two different conditions. For example,
Column A Column B Column C
1234 3 True
1234 5 False
5678 10 True
5678 15 False
So basically i want to find the difference in Column B when column A is the same but Column C is different.
If we can assume
2 rows for a given value in ColumnA
expected result is only 1 row returned per unique colA value
columnC will never be null...
Column B will never match, and if they do, you don't want the record returned.
We can use a self join checking for matches on column A, no matches on column C and so that we don't get a row each for 1234 of 2 and -2.
SELECT Z.ColumnA, Z.B-Y.B
FROM TableName Z
INNER JOIN tableName Y
on Z.ColumnA = Y.ColumnA
and Z.ColumnC <> Y.ColumnC
and Z.ColumnB > Y.ColumnB
you could also do this with a window function using lead and look ahead to the next record. but I don't know if your RDBMS supports window functions.
select t1.ColumnA, t1.ColumnB-t2.ColumnB diff from
tab t1, tab t2
where t1.columnA = t2.columnA and t1.ColumnC='True' and t2.ColumnC='False'
If your table name is myTable, I believe you can join the table with itself and on Column A and then select a difference in Column B when Column C is not equal to itself. So something like this
SELECT X.ColumnB - Y.ColumnB as Diff
FROM myTable as X
inner join
myTable as Y
on X.ColumnA=Y.ColumnA
WHERE X.ColumnC <> Y.ColumnC
You could use a self join
select a.column_A, a,column_B, b.column_B, a.column_B . b.column_B
from my_table a
inner join my_column b where a.column_a = b.column_a and a.column_c <> b_column_c
If you RDBMS supports window functions
;with cte as (
Select *
,Change = ColumnB-Lag(ColumnB,1) over (Partition By ColumnA Order By (Select null))
,TrueFalse = Lag(ColumnC,1) over (Partition By ColumnA Order By (Select null))
From #YourTable
)
Select ColumnA
,Change
From cte
Where Change<>0
and TrueFalse<>ColumnC
Returns
ColumnA Change
1234 2
5678 5
This one subtracts the "true" rows from the "false" rows, while preserving all true rows.
SELECT true.columna, true.columnb, COALESCE(false.columnb, 0) - true.columnb AS difference
FROM
(SELECT *
FROM t
WHERE columnc = "true") true
LEFT JOIN
(SELECT *
FROM t
WHERE columnc = "false) false
ON true.columna = false.columna
The coalesce clause will account for cases in which there is no false row. Without it you will end up trying to subtract from NULL.
If you're using Oracle, take a look at User Defined aggregate functions. If you define a function called diff(), then you can use select column_A, diff(column_B) from my_table group by column_A, but remember that the implementation of diff needs special care as different ordering will generate different results.

Assign null if subquery retrieves multiple records. How can it be done?

I have the following query. I simplified it for demo purpose. I am using SQL Server - t-sql
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID )
from tblMain tm
if the subquery returns multiple records, I like to assign tm.LocID to null else if there is only 1 record returned then assign it to tm.LocID. I am looking for a simple way to do this. Any help would be appreciated.
One way I can see is to have a CASE statement and check if (Count * > 1 ) then assign null else return the value but that would require a select statement within a select statement.
You have the right idea about using a case expression for count(*), but it will not require another subquery:
SELECT tm.LocID = (SELECT CASE COUNT(*) WHEN 1 THEN MAX(LocID) END
FROM tblLoc tl
WHERE tl.LocID = tm.LodID )
FROM tblMain tm
or just use a HAVING clause, like
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID
group by locID
having count(*) = 1)
)
from tblMain tm
Your query above (and many of the other answers here) is a correlated subquery which will be very slow since it performs a separate aggregation query on each record. This following will address both your problem and potentially perform a bit better since the count happens in a single pass.
SELECT
CASE
WHEN x.locid IS NOT NULL THEN x.locid
ELSE NULL
END
FROM tblMain m
LEFT JOIN (
SELECT
locid
FROM tblLoc
GROUP BY locid
HAVING COUNT(1) = 1
) x
ON x.locid = m.locid
;
The above is in Postgres syntax (what I'm familiar with) so you would have to make it TSQL compatible.