Need help in creating a view in sql with following data - sql

the table I am working on contains data in following format
Name | A | B | C
----------------
abc | 1 | 0 | 1
xyz | 0 | 1 | 1
pqr | 0 | 0 | 1
I need to create a view a like this
Name | Type
abc | A
abc | C
xyz | B
xyz | C
pqr | C
Will using case and when be helpful?
like
case when A=1 then 'A'
when B=1 then 'B'
when C=1 then 'C'
else ''
end as type
Thanks in advance!

Sample Table :
DECLARE #Table1 TABLE
(Name varchar(3), A int, B int, C int)
;
INSERT INTO #Table1
(Name, A, B, C)
VALUES
('abc', 1, 0, 1),
('xyz', 0, 1, 1),
('pqr', 0, 0, 1)
;
Script
Select Name,[Type] from (
select Name,CASE WHEN VAL = 1 then COL ELSE NULL END Type,VAL from #Table1
CROSS APPLY(VALUES('A',A),('B',B),('C',C))CS(COL,VAL)
)T WHERE T.Type IS NOT NULL

You can use union all
select name,'A' from t where a = 1 union all
select name,'B' from t where b = 1 union all
select name,'C' from t where c = 1;
You can also group the where condition as:
select name, col
from
(select name, 'A' col, a val from t union all
select name, 'B', b from t union all
select name, 'C', c from t)
where val = 1;

We can use union all to select all the records from the table and insert into the view. The Below query would suffice your requirement. Thank you.
create or replace view test1 as (
select name,field from (
select name,'A' as field from test where a = 1 union all
select name,'B' as field from test where b = 1 union all
select name,'C' as field from test where c = 1));

Related

Select rows when a value appears multiple times

I have a table like this one:
+------+------+
| ID | Cust |
+------+------+
| 1 | A |
| 1 | A |
| 1 | B |
| 1 | B |
| 2 | A |
| 2 | A |
| 2 | A |
| 2 | B |
| 3 | A |
| 3 | B |
| 3 | B |
+------+------+
I would like to get the IDs that have at least two times A and two times B. So in my example, the query should return only the ID 1,
Thanks!
In MySQL:
SELECT id
FROM test
GROUP BY id
HAVING GROUP_CONCAT(cust ORDER BY cust SEPARATOR '') LIKE '%aa%bb%'
In Oracle
WITH cte AS ( SELECT id, LISTAGG(cust, '') WITHIN GROUP (ORDER BY cust) custs
FROM test
GROUP BY id )
SELECT id
FROM cte
WHERE custs LIKE '%aa%bb%'
I would just use two levels of aggregation:
select id
from (select id, cust, count(*) as cnt
from t
where cust in ('A', 'B')
group by id, cust
) ic
group by id
having count(*) = 2 and -- both customers are in the result set
min(cnt) >= 2 -- and there are at least two instances
This is one option; lines #1 - 13 represent sample data. Query you might be interested in begins at line #14.
SQL> with test (id, cust) as
2 (select 1, 'a' from dual union all
3 select 1, 'a' from dual union all
4 select 1, 'b' from dual union all
5 select 1, 'b' from dual union all
6 select 2, 'a' from dual union all
7 select 2, 'a' from dual union all
8 select 2, 'a' from dual union all
9 select 2, 'b' from dual union all
10 select 3, 'a' from dual union all
11 select 3, 'b' from dual union all
12 select 3, 'b' from dual
13 )
14 select id
15 from (select
16 id,
17 sum(case when cust = 'a' then 1 else 0 end) suma,
18 sum(case when cust = 'b' then 1 else 0 end) sumb
19 from test
20 group by id
21 )
22 where suma = 2
23 and sumb = 2;
ID
----------
1
SQL>
You can use group by and having for the relevant Cust ('A' , 'B')
And query twice (I chose to use with to avoid multiple selects and to cache it)
with more_than_2 as
(
select Id, Cust, count(*) c
from tab
where Cust in ('A', 'B')
group by Id, Cust
having count(*) >= 2
)
select *
from tab
where exists ( select 1 from more_than_2 where more_than_2.Id = tab.Id and more_than_2.Cust = 'A')
and exists ( select 1 from more_than_2 where more_than_2.Id = tab.Id and more_than_2.Cust = 'B')
What you want is a perfect candidate for match_recognize. Here you go:
select id_ as id from t
match_recognize
(
order by id, cust
measures id as id_
pattern (A {2, } B {2, })
define A as cust = 'A',
B as cust = 'B'
)
Output:
Regards,
Ranagal

SQL for the below requirements

I am having trouble framing a SQL to get the desired outputs.
Table X
Id_X | GroupId | SomeColumn
Table R
Id_R | Id_X | GroupId | RColumn
The objective is to pick Id_X from Table R that have only GroupId values (A,B) and RColumn value is RValue
Ex:
Table X
1 | A | SomeValue
1 | B | SomeValue
2 | A | SomeValue
2 | B | SomeValue
2 | B | SomeValue
2 | C | SomeValue
Table R
101 | 1 | A | RValue
102 | 2 | A | RValue
The SQL should return 1
SELECT
[X].Id_X
FROM
[R]
INNER JOIN [X] ON
[R].Id_X = [X].Id_X
AND
[R].GroupId = [X].GroupId
WHERE
[X].GroupId IN ( 'A', 'B' )
AND
[R].RColumn = 'RValue'
If i understand correctly, your query should be
DECLARE #TableX AS TABLE
(
Id_X int, GroupId varchar(10), SomeColumn varchar(20)
)
INSERT INTO #TableX
VALUES
( 1, 'A', 'SomeValue'),
( 1, 'B', 'SomeValue'),
( 2, 'A', 'SomeValue'),
( 2, 'B', 'SomeValue'),
( 2, 'B', 'SomeValue'),
( 2, 'C', 'SomeValue')
DECLARE #TableR AS TABLE
(
ID_R int, Id_X int, GroupId varchar(10),RColumn varchar(10)
)
INSERT INTO #TableR
VALUES (101,1,'A','RValue'), (102,2,'A','RValue')
SELECT DISTINCT tr.Id_X
FROM #TableR tr
INNER JOIN #TableX tx ON tx.Id_X = tr.Id_X AND tx.GroupId = tr.GroupId
WHERE tr.RColumn = 'RValue'
AND NOT EXISTS ( SELECT 1 FROM #TableX tx2
WHERE tx2.Id_X = tx.Id_X
AND tx2.GroupId NOT IN ('A','B')
)
Demo link: http://rextester.com/EGLOT75874

How to subtract two rows from one another if they have they share a value in another column

I am currently working in a database with the following structure:
Var | Value | ID
--------------
A | 1 | 1
B | 2 | 1
C | 3 | 1
A | 2 | 2
B | 4 | 2
C | 6 | 2
What I am trying to achieve is to subtract the value of Var C from the other Var's (B and C) sharing the same ID as Var C. In this case the output would be:
Var | Value | ID
--------------
A | -2 | 1
B | -1 | 1
C | 3 | 1
A | -4 | 2
B | -2 | 2
C | 6 | 2
To be honest I have absolutely no idea how to start on achieving this. I am familiar with many other programming languages, but SQL is still a challenge with difficult/specific queries.
Do a self join:
select t1.var,
case when t1.var = 'C' then t1.value
else t1.value - t2.value
end as value,
t1.id
from tablename t1
join tablename t2 ON t1.id = t2.id
where t2.var = 'C'
Note that value is a reserved word in ANSI SQL, so it should be delimited as "Value".
You could pre-analyse the "C" Values and then use this to remove them?
DECLARE #Data TABLE (
[Var] VARCHAR(1),
Value INT,
ID INT);
INSERT INTO #Data SELECT 'A', 1, 1;
INSERT INTO #Data SELECT 'B', 2, 1;
INSERT INTO #Data SELECT 'C', 3, 1;
INSERT INTO #Data SELECT 'A', 2, 2;
INSERT INTO #Data SELECT 'B', 4, 2;
INSERT INTO #Data SELECT 'C', 6, 2;
WITH CValues AS (
SELECT
ID,
Value
FROM
#Data
WHERE
[Var] = 'C')
SELECT
d.[Var],
CASE WHEN d.[Var] != 'C' THEN d.Value - c.Value ELSE d.Value END AS Value,
d.ID
FROM
#Data d
LEFT JOIN CValues c ON c.ID = d.ID;
...but yes, a self-join is probably a better solution:
DECLARE #Data TABLE (
[Var] VARCHAR(1),
Value INT,
ID INT);
INSERT INTO #Data SELECT 'A', 1, 1;
INSERT INTO #Data SELECT 'B', 2, 1;
INSERT INTO #Data SELECT 'C', 3, 1;
INSERT INTO #Data SELECT 'A', 2, 2;
INSERT INTO #Data SELECT 'B', 4, 2;
INSERT INTO #Data SELECT 'C', 6, 2;
SELECT
d.[Var],
CASE WHEN d.[Var] != 'C' THEN d.Value - c.Value ELSE d.Value END AS Value,
d.ID
FROM
#Data d
LEFT JOIN #Data c ON c.[Var] = 'C' AND c.ID = d.ID;

How to comapre two columns of a table in sql?

In a table there are two columns:
-----------
| A | B |
-----------
| 1 | 5 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
-----------
Want a table where if A=B then
-------------------
|Match | notMatch|
-------------------
| 1 | 5 |
| 2 | 3 |
| Null | 4 |
-------------------
How can i do this?
I tried something which shows the Matched part
select distinct C.A as A from Table c inner join Table d on c.A=d.B
Try this:
;WITH TempTable(A, B) AS(
SELECT 1, 5 UNION ALL
SELECT 2, 1 UNION ALL
SELECT 3, 2 UNION ALL
SELECT 4, 1
)
,CTE(Val) AS(
SELECT A FROM TempTable UNION ALL
SELECT B FROM TempTable
)
,Match AS(
SELECT
Rn = ROW_NUMBER() OVER(ORDER BY Val),
Val
FROM CTE c
GROUP BY Val
HAVING COUNT(Val) > 1
)
,NotMatch AS(
SELECT
Rn = ROW_NUMBER() OVER(ORDER BY Val),
Val
FROM CTE c
GROUP BY Val
HAVING COUNT(Val) = 1
)
SELECT
Match = m.Val,
NotMatch= n.Val
FROM Match m
FULL JOIN NotMatch n
ON n.Rn = m.Rn
Try with EXCEPT, MINUS and INTERSECT Statements.
like this:
SELECT A FROM TABLE1 INTERSECT SELECT B FROM TABLE1;
You might want this:
SELECT DISTINCT
C.A as A
FROM
Table c
LEFT OUTER JOIN
Table d
ON
c.A=d.B
WHERE
d.ID IS NULL
Please Note that I use d.ID as an example because I don't see your schema. An alternate is to explicitly state all d.columns IS NULL in WHERE clause.
Your requirement is kind of - let's call it - interesting. Here is a way to solve it using pivot. Personally I would have chosen a different table structure and another way to select data:
Test data:
DECLARE #t table(A TINYINT, B TINYINT)
INSERT #t values
(1,5),(2,1),
(3,2),(4,1)
Query:
;WITH B AS
(
( SELECT A FROM #t
EXCEPT
SELECT B FROM #t)
UNION ALL
( SELECT B FROM #t
EXCEPT
SELECT A FROM #t)
), A AS
(
SELECT A val
FROM #t
INTERSECT
SELECT B
FROM #t
), combine as
(
SELECT val, 'A' col, row_number() over (order by (select 1)) rn FROM A
UNION ALL
SELECT A, 'B' col, row_number() over (order by (select 1)) rn
FROM B
)
SELECT [A], [B]
FROM combine
PIVOT (MAX(val) FOR [col] IN ([A], [B])) AS pvt
Result:
A B
1 3
2 4
NULL 5

SQL selection over two rows

How do I select in a table like below all objects that have a-A and b-B (as key-value pair)?
Something like:
SELECT DISTINCT(OBJECT)
FROM MYTABLE
WHERE key = 'a'
AND value = 'A'
AND key = 'b'
AND value = 'B'
...where the result would be 1 and 3.
I know that this SQL statement doesn't work, but I hope it explains a bit what I want to do.
And sorry for the diffuse title. I simply don't know how to describe the problem better.
object | key | value
---------------------
1 | a | A
1 | b | B
1 | c | C
2 | a | F
2 | b | B
3 | a | A
3 | b | B
3 | d | D
I think you want something of this form:
SELECT a.object
FROM mytable a, mytable b
WHERE a.object = b.object
AND a.key = 'a' AND a.value = 'A'
AND b.key = 'b' AND b.value = 'B'
select *
from mytable
where (key = a and value = a)
or (key = b and value = b)
or
select *
from mytable
where key = a and value = a
union
select *
from mytable
where key = b and value = b
or more generally perhaps
select *
from mytable
where key = value
and key in (a,b)
You can even try this
declare #t table(object int, keys varchar(10), value varchar(10))
insert into #t
select 1,'a','A' union all select 1,'b','B' union all
select 1,'c','C' union all
select 2,'a','F' union all select 2,'b','B' union all
select 3,'a','A' union all select 3,'b','B' union all
select 3,'d','D'
--select * from #t
Query
select object from #t
where keys = 'a' and value ='A'
or keys = 'b' and value ='B'
group by object
having COUNT(object)>1
Output:
object
1
3