SQL displaying the specific column - sql

How should I write a query that only shows the inside column values with "YES" ?
Hospital_ID MATERINITY ENT DERMATOLOGY ORTHOPEDICS
1 YES NO NO NO
2 YES YES NO NO
3 YES YES NO YES
The result I'm looking for is Hospital_ID "3":
Hospital_ID MATERINITY ENT ORTHOPEDICS
3 YES YES YES
that won't show the column with value "NO".

Well if you're only looking to exclude the dermatology column when it's NO and you don't care about any of the other columns being NO (unless they're all NO) then it would be:
SELECT Hospital_ID, MATERNITY, ENT, ORTHOPEDICS,
FROM DepartmentTable
WHERE DERMATOLOGY = 'NO' AND (MATERNITY = 'YES' OR ENT = 'YES' OR ORTHOPEDICS = 'YES');
This would only give you the rows where DERMATOLOGY is NO but there is another column with a 'YES' value. I'm assuming you don't want results where all columns are 'NO'.

You're going to get into trouble trying to drop columns, especially when you include multiple hospitals. I would recommend doing the yesses as rows with a union query, then you can crosstab in your report.
SELECT Hospital_ID, 'MATERNITY' Dept FROM myTable t WHERE t.MATERNITY='YES'
UNION SELECT Hospital_ID, 'ENT' Dept FROM myTable t WHERE t.ENT='YES'
UNION SELECT Hospital_ID, 'DERMATOLOGY' Dept FROM myTable t WHERE t.DERMATOLOGY='YES'
UNION SELECT Hospital_ID, 'ORTHOPEDICS' Dept FROM myTable t WHERE t.ORTHOPEDICS='YES'
If you need to filter for hospital id = 3 then do:
SELECT Hospital_ID, Dept FROM (
SELECT Hospital_ID, 'MATERNITY' Dept FROM myTable t WHERE t.MATERNITY='YES'
UNION SELECT Hospital_ID, 'ENT' Dept FROM myTable t WHERE t.ENT='YES'
UNION SELECT Hospital_ID, 'DERMATOLOGY' Dept FROM myTable t WHERE t.DERMATOLOGY='YES'
UNION SELECT Hospital_ID, 'ORTHOPEDICS' Dept FROM myTable t WHERE t.ORTHOPEDICS='YES') x
WHERE Hospital_ID=3

Try
SELECT *
FROM TableName
WHERE MATERINITY = "YES" AND
DERMATOLOGY = "YES" AND
ORTHOPEDICS = "YES"

Related

SQL Server - find horizontal occurrences

I am using SQL Server 2008R2 and have tableA that has four columns res_id,res_id2,res_id3,res_id4 numeric.
I want to find away to find the occurrences of the same IDs on each row (the met column) excluding 0 or null
Example:
golf_id res_id res_id2 res_id3 res_id4 met
1579 2068252 2068252 NULL 0 1
1492 2076015 2076015 2076016 2076016 2
1494 2076046 2076046 2076046 2076047 2
1617 2077041 2077042 2077043 2077044 4
1545 2076102 2076102 NULL NULL 1
So in the first row I have only 2068252 so met should be 1
In the second row I have 2076015 and 2076016 so met should be 2
In the third row I have 2076046 and 2076047 so met should be 2
In the fourth row I have 2077041, 2077042, 2077043, 2077044 so met
should be 4
In the fifth row I have 2076102 so met should be 1
Thank you
A simple solution would be to unpivot your data, and then COUNT the DISTINCT values. I'm pretty sure this'll work on 2008 R2 (though I don't have access to such an instance, nor have had access to one for the best part of a decade).
WITH YourTable AS(
SELECT *
FROM (VALUES(1579,2068252,2068252,NULL ,0 ),
(1492,2076015,2076015,2076016,2076016),
(1494,2076046,2076046,2076046,2076047),
(1617,2077041,2077042,2077043,2077044),
(1545,2076102,2076102,NULL ,NULL ))V(golf_id,res_id,res_id2,res_id3,res_id4))
SELECT YT.golf_id,
YT.res_id,
YT.res_id2,
YT.res_id3,
YT.res_id4,
(SELECT COUNT(DISTINCT NULLIF(V.res_id,0))
FROM (VALUES(res_id),(res_id2),(res_id3),(res_id4))V(res_id)) met
FROM YourTable YT;
Generic way to do is something like this:
select
a.golf_id
, a.res_id
, a.res_id2
, a.res_id3
, a.res_id4
, b.met
from (
select b.golf_id, count(distinct res_id) as met
from (
select golf_id, res_id from tableA where res_id > 0
union all
select golf_id, res_id2 from tableA where res_id2 > 0
union all
select golf_id, res_id3 from tableA where res_id3 > 0
union all
select golf_id, res_id4 from tableA where res_id4 > 0
) as b
group by b.golf_id
) as b
join tableA as a
on a.golf_id = b.golf_id

Pivoting Multiple Attributres and grouping them as a 'single' attribute (many to one)

So I Have a table called Value that's associated with different 'Fields'. Note that some of these fields have similar 'names' but they are named differently. Ultimately I want these 'similar names' to be pivoted/grouped as the same field name in the result set
VALUE_ID VALUE_TX FIELD_NAME Version_ID
1 Yes Adult 1
2 18 Age 1
3 Black Eye Color 1
4 Yes Is_Adult 2
5 25 Years_old 2
6 Brown Color_of_Eyes 2
I have a table called Submitted that looks like the following:
Version_ID Version_Name
1 TEST_RUN
2 REAL_RUN
I need a result set that Looks like this:
Submitted_Name Adult? Age Eye_Color
TEST_RUN Yes 18 Black
REAL_RUN Yes 25 Brown
I've tried the following:
SELECT * FROM (
select value_Tx, field_name, version_id
from VALUE
)
PIVOT (max (value_tx) for field_name in (('Adult', 'Is_Adult') as 'Adult?', ('Age', 'Years_old') as 'Age', ('Eye Color', 'Color_of_Eyes') as 'Eye_Color')
);
What am I doing wrong? Please let me know if I need to add any additional details / data.
Thanks in advance!
The error message that I am getting is the following:
ORA-00907: missing right parenthesis
I would change the field names in the subquery:
SELECT *
FROM (select value_Tx,
(case when field_name in ('Adult', 'Is_Adult') then 'Adult?'
field_name in ('Age', 'Years_old') then 'Age'
field_name in ('Eye Color', 'Color_of_Eyes') then 'Eye_Color'
else field_name
end) as field_name, version_id
from VALUE
)
PIVOT (max(value_tx) for field_name in ('Adult?', 'Age', 'Eye_Color'));
You can use double quotes for column aliasing within the pivot clause's part, and I think decode function suits well for this question. You can consider using the following query :
with value( value_id, value_tx, field_name, version_id ) as
(
select 1 ,'Yes' ,'Adult' ,1 from dual union all
select 2 ,'18' ,'Age' ,1 from dual union all
select 3 ,'Black','Eye_Color' ,1 from dual union all
select 4 ,'Yes' ,'Is_Adult' ,2 from dual union all
select 5 ,'25' ,'Years_old' ,2 from dual union all
select 6 ,'Brown','Color_of_Eyes',2 from dual
), Submitted( version_id, version_name ) as
(
select 1 ,'TEST_RUN' from dual union all
select 2 ,'REAL_RUN' from dual
)
select * from
(
select s.version_name as "Submitted_Name", v.value_Tx,
decode(v.field_name,'Adult','Is_Adult','Age','Years_old','Eye_Color',
'Color_of_Eyes',v.field_name) field_name
from value v
join Submitted s
on s.version_id = v.version_id
group by decode(v.field_name,'Adult','Is_Adult','Age','Years_old','Eye_Color',
'Color_of_Eyes',v.field_name),
v.value_Tx, s.Version_Name
)
pivot(
max(value_tx) for field_name in ( 'Is_Adult' as "Adult?", 'Years_old' as "Age",
'Color_of_Eyes' as "Eye_Color" )
);
Submitted_Name Adult? Age Eye_Color
REAL_RUN Yes 25 Brown
TEST_RUN Yes 18 Black
I think, better to solve as much as shorter way, as an example, using modular arithmetic would even be better as below :
select *
from
(
select s.version_name as "Submitted_Name", v.value_Tx, mod(v.value_id,3) as value_id
from value v
join Submitted s
on s.version_id = v.version_id
group by v.value_Tx, s.version_name, mod(v.value_id,3)
)
pivot(
max(value_tx) for value_id in ( 1 as "Adult?", 2 as "Age", 0 as "Eye_Color" )
)
Demo

SQL query to get column names if it has specific value

I have a situation here, I have a table with a flag assigned to the column names(like 'Y' or 'N'). I have to select the column names of a row, if it have a specific value.
My Table:
Name|sub-1|sub-2|sub-3|sub-4|sub-5|sub-6|
-----------------------------------------
Tom | Y | | Y | Y | | Y |
Jim | Y | Y | | | Y | Y |
Ram | | Y | | Y | Y | |
So I need to get, what are all the subs are have 'Y' flag for a particular Name.
For Example:
If I select Tom I need to get the list of 'Y' column name in query output.
Subs
____
sub-1
sub-3
sub-4
sub-6
Your help is much appreciated.
The problem is that your database model is not normalized. If it was properly normalized the query would be easy. So the workaround is to normalize the model "on-the-fly" to be able to make the query:
select col_name
from (
select name, sub_1 as val, 'sub_1' as col_name
from the_table
union all
select name, sub_2, 'sub_2'
from the_table
union all
select name, sub_3, 'sub_3'
from the_table
union all
select name, sub_4, 'sub_4'
from the_table
union all
select name, sub_5, 'sub_5'
from the_table
union all
select name, sub_6, 'sub_6'
from the_table
) t
where name = 'Tom'
and val = 'Y'
The above is standard SQL and should work on any (relational) DBMS.
Below code works for me.
select t.Subs from (select name, u.subs,u.val
from TableName s
unpivot
(
val
for subs in (sub-1, sub-2, sub-3,sub-4,sub-5,sub-6,sub-7)
) u where u.val='Y') T
where t.name='Tom'
Somehow I am near to the solution. I can get for all rows. (I just used 2 columns)
select col from ( select col, case s.col when 'sub-1' then sub-1 when 'sub-2' then sub-2 end AS val from mytable cross join ( select 'sub-1' AS col union all select 'sub-2' ) s ) s where val ='Y'
It gives the columns for all row. I need the same data for a single row. Like if I select "Tom", I need the column names for 'Y' value.
I'm answering this under a few assumptions here. The first is that you KNOW the names of the columns of the table in question. Second, that this is SQL Server. Oracle and MySql have ways of performing this, but I don't know the syntax for that.
Anyways, what I'd do is perform an 'UNPIVOT' on the data.
There's a lot of parans there, so to explain. The actual 'unpivot' statement (aliased as UNPVT) takes the data and twists the columns into rows, and the SELECT associated with it provides the data that is being returned. Here's I used the 'Name', and placed the column names under the 'Subs' column and the corresponding value into the 'Val' column. To be precise, I'm talking about this aspect of the above code:
SELECT [Name], [Subs], [Val]
FROM
(SELECT [Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6]
FROM pvt) p
UNPIVOT
(Orders FOR [Name] IN
([Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6])
)AS unpvt
My next step was to make that a 'sub-select' where I could find the specific name and val that was being hunted for. That would leave you with a SQL Statement that looks something along these lines
SELECT [Name], [Subs], [Val]
FROM (
SELECT [Name], [Subs], [Val]
FROM
(SELECT [Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6]
FROM pvt) p
UNPIVOT
(Orders FOR [Name] IN
([Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6])
)AS unpvt
) AS pp
WHERE 1 = 1
AND pp.[Val] = 'Y'
AND pp.[Name] = 'Tom'
select col from (
select col,
case s.col
when 'sub-1' then sub-1
when 'sub-2' then sub-2
when 'sub-3' then sub-3
when 'sub-4' then sub-4
when 'sub-5' then sub-5
when 'sub-6' then sub-6
end AS val
from mytable
cross join
(
select 'sub-1' AS col union all
select 'sub-2' union all
select 'sub-3' union all
select 'sub-4' union all
select 'sub-5' union all
select 'sub-6'
) s on name="Tom"
) s
where val ='Y'
included the join condition as
on name="Tom"

Splitting rows to columns in oracle

I have data in a table which looks like:
I want to split its data and make it look like the following through a sql query in Oracle (without using pivot):
How can it be done?? is there any other way of doing so without using pivot?
You need to use a pivot query here to get the output you want:
SELECT Name,
MIN(CASE WHEN ID_Type = 'PAN' THEN ID_No ELSE NULL END) AS PAN,
MIN(CASE WHEN ID_Type = 'DL' THEN ID_No ELSE NULL END) AS DL,
MIN(CASE WHEN ID_Type = 'Passport' THEN ID_No ELSE NULL END) AS Passport
FROM yourTable
GROUP BY Name
You could also try using Oracle's built in PIVOT() function if you are running version 11g or later.
Since you mention without using PIVOT function, you can try to
use SQL within group for moving rows onto one line and listagg to display multiple column values in a single column.
In Oracle 11g, we can use the listagg built-in function :
select
deptno,
listagg (ename, ',')
WITHIN GROUP
(ORDER BY ename) enames
FROM
emp
GROUP BY
deptno
Which should give you the below result:
DEPTNO ENAMES
------ --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
You can find all the solution(s) to this problem here:
http://www.dba-oracle.com/t_converting_rows_columns.htm
For Oracle 11g and above, you could use PIVOT.
For pre-11g release, you could use MAX and CASE.
A common misconception, about PIVOT better in terms of performance than the old way of MAX and DECODE. But, under the hood PIVOT is same MAX + CASE. You can check it in 12c where Oracle added EXPAND_SQL_TEXT procedure to DBMS_UTILITY package.
For example,
SQL> variable c clob
SQL> begin
2 dbms_utility.expand_sql_text(Q'[with choice_tbl as (
3 select 'Jones' person,1 choice_nbr,'Yellow' color from dual union all
4 select 'Jones',2,'Green' from dual union all
5 select 'Jones',3,'Blue' from dual union all
6 select 'Smith',1,'Orange' from dual
7 )
8 select *
9 from choice_tbl
10 pivot(
11 max(color)
12 for choice_nbr in (1 choice_nbr1,2 choice_nbr2,3 choice_nbr3)
13 )]',:c);
14 end;
15 /
PL/SQL procedure successfully completed.
Now let's see what Oracle actually does internally:
SQL> set long 100000
SQL> print c
C
--------------------------------------------------------------------------------
SELECT "A1"."PERSON" "PERSON",
"A1"."CHOICE_NBR1" "CHOICE_NBR1",
"A1"."CHOICE_NBR2" "CHOICE_NBR2",
"A1"."CHOICE_NBR3" "CHOICE_NBR3"
FROM (
SELECT "A2"."PERSON" "PERSON",
MAX(CASE WHEN ("A2"."CHOICE_NBR"=1) THEN "A2"."COLOR" END ) "CHOICE_NBR1",
MAX(CASE WHEN ("A2"."CHOICE_NBR"=2) THEN "A2"."COLOR" END ) "CHOICE_NBR2",
MAX(CASE WHEN ("A2"."CHOICE_NBR"=3) THEN "A2"."COLOR" END ) "CHOICE_NBR3"
FROM (
(SELECT 'Jones' "PERSON",1 "CHOICE_NBR",'Yellow' "COLOR" FROM "SYS"."DUAL" "A7") UNION ALL
(SELECT 'Jones' "'JONES'",2 "2",'Green' "'GREEN'" FROM "SYS"."DUAL" "A6") UNION ALL
(SELECT 'Jones' "'JONES'",3 "3",'Blue' "'BLUE'" FROM "SYS"."DUAL" "A5") UNION ALL
(SELECT 'Smith' "'SMITH'",1 "1",'Orange' "'ORANGE'" FROM "SYS"."DUAL" "A4")
) "A2"
GROUP BY "A2"."PERSON"
) "A1"
SQL>
Oracle internally interprets the PIVOT as MAX + CASE.
You're able to create a non-pivot query by understanding what the pivot query will do:
select *
from yourTable
pivot
(
max (id_no)
for (id_type) in ('PAN' as pan, 'DL' as dl, 'Passport' as passport)
)
What the pivot does is GROUP BY all columns not specified inside the PIVOT clause (actually, just the name column), selecting new columns in a subquery fashion based on the aggregations before the FOR clause for each value specified inside the IN clause and discarding those columns specified inside the PIVOT clause.
When I say "subquery fashion" I'm refering to one way to achieve the result got with PIVOT. Actually, I don't know how this works behind the scenes. This subquery fashion would be like this:
select <aggregation>
from <yourTable>
where 1=1
and <FORclauseColumns> = <INclauseValue>
and <subqueryTableColumns> = <PIVOTgroupedColumns>
Now you identified how you can create a query without the PIVOT clause:
select
name,
(select max(id_no) from yourTable where name = t.name and id_type = 'PAN') as pan,
(select max(id_no) from yourTable where name = t.name and id_type = 'DL') as dl,
(select max(id_no) from yourTable where name = t.name and id_type = 'Passport') as passport
from yourTable t
group by name
You can use CTE's to break the data down and then join them back together to get what you want:
WITH NAMES AS (SELECT DISTINCT NAME
FROM YOURTABLE),
PAN AS (SELECT NAME, ID_NO AS PAN
FROM YOURTABLE
WHERE ID_TYPE = 'PAN'),
DL AS (SELECT NAME, ID_NO AS DL
FROM YOURTABLE
WHERE ID_TYPE = 'DL'),
PASSPORT AS (SELECT NAME, ID_NO AS "Passport"
FROM YOURTABLE
WHERE ID_TYPE = 'Passport')
SELECT n.NAME, p.PAN, d.DL, t."Passport"
FROM NAMES n
LEFT OUTER JOIN PAN p
ON p.NAME = n.NAME
LEFT OUTER JOIN DL d
ON d.NAME = p.NAME
LEFT OUTER JOIN PASSPORT t
ON t.NAME = p.NAME'
Replace YOURTABLE with the actual name of your table of interest.
Best of luck.

How to check existence of data in a table from a where clause in sql server 2008?

Suppose I have a table with columns user_id, name and the table contains data like this:
user_id name
------- -----
sou souhardya
cha chanchal
swa swapan
ari arindam
ran ranadeep
If I want to know these users (sou, cha, ana, agn, swa) exists in this table or not then I want output like this:
user_id it exists or not
------- -----------------
sou y
cha y
ana n
agn n
swa y
As ana and aga do not exist in the table it must show "n" (like the above output).
Assuming your existing checklist is not on the database, you will have to assemble a query containing those. There are many ways of doing it. Using CTEs, it would look like this:
with cte as
(
select 'sou' user_id
union all
select 'cha'
union all
select 'ana'
union all
select 'agn'
union all
select 'swa'
)
select
cte.user_id,
case when yt.user_id is null then 'n' else 'y' end
from cte
left join YourTable yt on cte.user_id = yt.user_id
This also assumes user_id is unique.
Here is the SQLFiddle with the proof of concept: http://sqlfiddle.com/#!3/e023a0/4
Assuming you're just testing this manually:
DECLARE #Users TABLE
(
[user_id] VARCHAR(50)
)
INSERT INTO #Users
SELECT 'sou'
UNION SELECT 'cha'
UNION SELECT 'ana'
UNION SELECT 'agn'
UNION SELECT 'swa'
SELECT a.[user_id]
, [name]
, CASE
WHEN b.[user_id] IS NULL THEN 'N'
ELSE 'Y'
END AS [exists_or_not]
FROM [your_table] a
LEFT JOIN #Users b
ON a.[user_id] = b.[user_id]
You didn't provide quite enough information to provide a working example, but this should get you close:
select tbl1.user_id, case tbl2.user_id is null then 'n' else 'y' end
from tbl1 left outer join tbl2 on tbl1.user_id = tbl2.user_id
;with usersToCheck as
(
select 'sou' as userid
union select 'cha'
union select 'ana'
union select 'agn'
union select 'swa'
)
select utc.userid,
(case when exists ( select * from usersTable as ut where ut.user_id = utc.userid) then 'y' else 'n' end)
from usersToCheck as utc