Selecting multiple rows of a column in a SQL Server query - sql

I have a table, let's call it Case the case table contains basic information about a case, such as the CaseNumber and the CaseOwner.
In a separate table, CaseDetails a number of phone numbers associated with a particular case are stored. The Type column within CaseDetails represents the type of phone number e.g. Home, mobile or work. These two tables link on CaseNumber.
More clearly:
Case
CaseNumber CaseOwner
------------------------
1 Bob
2 Jim
3 Gary
CaseDetails
CaseNumber Detail Type
----------------------------------
1 0123456789 1
1 1111111111 2
2 2222222222 1
1 0101001011 3
2 1234123412 2
3 0000011111 1
3 1231231231 2
I want to be able to write a query that can pull back the basic details of a case, as well as ALL of the associated phone numbers.
In my head I imagined the query to go something like the following
Select
CaseNumber, CaseOwner,
Detail where Type = 1, Detail where Type = 2, Detail where Type = 3
From
Case
Join
CaseDetails on Case.CaseNumber = CaseDetails.CaseNumber
That way each individual Detail could be extracted from the CaseDetails table using the type column. However this is syntactically incorrect and won't execute.
How exactly would I construct a query to extract this information? I can't seem to find the information on this on Google as I'm not sure what to search for.
The whole point of this is so that I can find all of the associated numbers for a particular case and store them in one location.
This is what I want the final output to look like
CaseNumber CaseOwner Detail1 Detail2 Detail3
-------------------------------------------------------------------
1 Bob 0123456789 1111111111 0000011111

You can try below using CASE WHEN expression
Select a.CaseNumber, CaseOwner, max(case when Type = 1 then detail end) as as detail1, max(case when Type = 2 then detail end) as detail2, max(case when Type = 3 then detail end) as detail3
From Case a
Join CaseDetails b on a.CaseNumber = b.CaseNumber
group by a.CaseNumber, CaseOwner
OR you can use PIVOT
with cte as
(
Select a.CaseNumber, CaseOwner, type, detail
From Case a
Join CaseDetails b on a.CaseNumber = b.CaseNumber
group by a.CaseNumber, CaseOwner
)
select casenumber, caseowner,pv.*
from cte pivot(max(detail) for type in (1,2,3)) as pv

You can use conditional aggregation:
Select c.CaseNumber, c.CaseOwner,
max(case when cd.type = 1 then cd.Detail end) as detail_1,
max(case when cd.type = 2 then cd.Detail end) as detail_2,
max(case when cd.type = 3 then cd.Detail end) as detail_3
From Case c Join
CaseDetails cd
on c.CaseNumber = cd.CaseNumber
group by c.CaseNumber, c.CaseOwner;
EDIT:
You can also do this using outer apply:
select c.*, cd.*
from case c outer apply
(select max(case when cd.type = 1 then cd.Detail end) as detail_1,
max(case when cd.type = 2 then cd.Detail end) as detail_2,
max(case when cd.type = 3 then cd.Detail end) as detail_3
from CaseDetails cd
where c.CaseNumber = cd.CaseNumber
) cd;

use pivot
select CaseNumber,CaseOwner,
[1] as detail1,
[2] as detail2 ,
[3] as detail3
from
(select c1.CaseNumber,c1.CaseOwner,c2.Detail,c2.Type
From Case c1
Join CaseDetails c2
on c1.CaseNumber = c2.CaseNumber
) src
PIVOT
(
max(Detail) for Type in ([1],[2],[3])
) pvt

Related

How to merge 2 tables into 1 row, with multiple entries from second table in Oracle SQL

newbee question on (Oracle) SQL.
I'd like this table :
ash_id ash_contact_name ash_contact_telefoonnummber
15313 Name1 022457852114
15313 Name2 122457852114
15313 Name3 222457852114
15313 Name4 322457852114
15313 Name5 422457852114
To Look like this in 1 row :
15313 Name1 022457852114 Name2 122457852114 Name3 222457852114 Name4 322457852114 Name5 422457852114
So I get only 1x the id from first table and multiple coloms with the name with My code now looks like this :
select ash.ash_id ,
con.ash_contact_name, con.ash_contact_telefoonnummer
from D00ASH01.ash_admin_stakeholder ash,ash_contacts con
where con.ash_id = ash.ash_id and con.ash_id = 15313
order by ash.ash_id
The eventual code while not include "con.ash_id = 15313" as I will need to have all the entries. The end result will include more fields from the first table, so I can not just use the second table alone. For now, I want to start to build it up simple.
I tried to make it work with a join but did not made it.
All suggestions welcome,
thanks
Check this, it might help you. If it is not then let me know.
SELECT ash.ash_id , con.ash_contact_name, con.ash_contact_telefoonnummer FROM D00ASH01.ash_admin_stakeholder as ash INNER JOIN ash_contacts as con ON con.ash_id = ash.ash_id WHERE con.ash_id = 15313 ORDER BY ash.ash_id;
SELECT * FROM ash INNER JOIN con USING( ash_id ) Where con_id = 15313 ORDER BY ash_id ;
I'did get the solution for this :
select
c.ash_id,
c.ash_naam_kbo_NL ,
c.ash_naam_kbo_FR ,
c.ash_naam_kbo_DE,
max(Case when rn = 1 then c.ASH_CONTACT_NAME else null end) as name1,
max(Case when rn = 1 then c.ASH_CONTACT_GSMNUMMER else null end) as gsm1,
max(Case when rn = 1 then c.ASH_CONTACT_FAXNUMMER else null end) as fax1,
max(Case when rn = 1 then c.ASH_CONTACT_EMAILADRES else null end) as email1,
max(Case when rn = 2 then c.ASH_CONTACT_NAME else null end) as name2,
max(Case when rn = 2 then c.ASH_CONTACT_GSMNUMMER else null end) as gsm2,
max(Case when rn = 2 then c.ASH_CONTACT_FAXNUMMER else null end) as fax2,
max(Case when rn = 2 then c.ASH_CONTACT_EMAILADRES else null end) as email2
from (
select
table_ash.ash_id,
table_ash.ash_naam_kbo_NL ,
table_ash.ash_naam_kbo_FR ,
table_ash.ash_naam_kbo_DE,
table_contacts.ASH_CONTACT_NAME,
table_contacts.ASH_CONTACT_GSMNUMMER,
table_contacts.ASH_CONTACT_FAXNUMMER,
table_contacts.ASH_CONTACT_EMAILADRES,
ROW_NUMBER () over (partition by table_ash.ash_id order by table_ash.ash_id,
table_ash.ash_naam_kbo_NL) rn
from
ASH_ADMIN_STAKEHOLDER table_ash,
ash_contacts table_contacts
where
table_ash.ash_id = table_contacts.ash_id) c
group by
c.ash_id,
c.ash_naam_kbo_NL ,
c.ash_naam_kbo_FR ,
c.ash_naam_kbo_DE;
So, there's a "select" from a "select". The trick is to generate a rownnumber and use it like a index. For as many as rownumbers as needed, include a max function in the query. This code is the base of answer I needed.
SQL code written in Oracle:
WITH CTE AS(
SELECT
            UP.CLASS,
            UP.NS || UP.RN AS NSR,
            UP.VAL
FROM
            (
            SELECT
                        ROW_NUMBER ()
         OVER (
           PARTITION BY S.CLASS
            ORDER BY
                        S.CLASS) RN,
                        S.*
            FROM
                        STAKEHOLDER S
            ORDER BY
                        CLASS,
                        SID) SS
UNPIVOT (VAL FOR NS IN (NAME, SID)) UP
)
SELECT
            *
FROM
            CTE
PIVOT(MAX(VAL) FOR NSR IN ('NAME1' AS NAME1,
            'SID1' AS SID1,
            'NAME2' AS NAME2,
            'SID2' AS SID2,
            'NAME3' AS NAME3,
            'SID3' AS SID3))
This is not difficult if we handle it with our natural way of thinking. After grouping the table by CLASS, we convert NAME and SID columns into rows and create names commanding values to be converted to columns. Format of names is the original column name + number of subgroups, like NAME1, SID1, NAME2, SID2,… for group 1 and NAME1, SID1, … for group2. Then we concatenate groups and transpose row to columns. The problem is SQL does not support dynamic row-to-column/column-to-row transposition. When the number of columns is small and columns are fixed, the language can mange to do the transpositions. As the number of columns increases, the scenario becomes more and more awkward. Enumerating all columns to be converted is complicated and SQL code becomes bloated. If columns are dynamic, SQL needs to turn to complex and roundabout ways to handle them.
Yet, it is really easy to code the transposition task with the open-source esProc SPL:
| |A|
|1|=connect("ORACLE")|
|2|=A1.query#x("SELECT \* FROM STAKEHOLDER ORDER BY CLASS,SID")|
|3|=A2.fname().m(2:)|
|4|=A2.group#o(CLASS)|
|5|=A4.conj(\~.news(A3;CLASS,A3(#)/A4.\~.#:COL,\~:VAL))|

SQL Joined Tables - Multiple rows on joined table per 'on' matched field merged into one row?

I have two tables I am pulling data from. Here is a minimal recreation of what I have:
Select
Jobs.Job_Number,
Jobs.Total_Amount,
Job_Charges.Charge_Code,
Job_Charges.Charge_Amount
From
DB.Jobs
Inner Join
DB.Job_Charges
On
Jobs.Job_Number = Job_Charges.Job_Number;
So, what happens is that I end up getting a row for each different Charge_Code and Charge_Amount per Job_Number. Everything else on the row is the same. Is it possible to have it return something more like:
Job_Number - Total_Amount - Charge_Code[1] - Charge_Amount[1] - Charge_Code[2] - Charge_Amount[2]
ETC?
This way it creates one line per job number with each associated charge and amount on the same line. I have been reading through W3 but haven't been able to tell definitively if this is possible or not. Anything helps, thank you!
To pivot your resultset over a fixed number of columns, you can use row_number() and conditional aggregation:
select
job_number,
total_amount,
max(case when rn = 1 then charge_code end) charge_code1,
max(case when rn = 1 then charge_amount end) charge_amount1,
max(case when rn = 2 then charge_code end) charge_code2,
max(case when rn = 2 then charge_amount end) charge_amount2,
max(case when rn = 3 then charge_code end) charge_code3,
max(case when rn = 3 then charge_amount end) charge_amount3
from (
select
j.job_number,
j.total_amount,
c.charge_code,
c.charge_amount,
row_number() over(partition by job_number, total_amount order by c.charge_code) rn
from DB.Jobs j
inner join DB.Job_Charges c on j.job_number = c.job_number
) t
group by job_number, total_amount
The above query handes up to 3 charge codes and amounts par job number (ordered by job codes). You can expand the select clause with more max(case ...) expressions to handle more of them.

SELECTING from same field in 2 column

I want to create a report that appears from the same field in two columns
example :
receipt id infotype information
-----------------------------------------------
1 phone number 123
1 comment no comment
2 phone number 12346
2 any comment price is high
Result :
receipt id phone number comment
----------------------------------------------
1 123 no comment
2 12346 price is high
I use this code but the result is not same I need:
SELECT
RETAILTRANSACTIONINFOCODETRANS.TRANSDATE AS "Date" ,
RETAILTRANSACTIONTABLE.RECEIPTID AS "Receipt number" ,
RETAILTRANSACTIONSALESTRANS.staff As "Staff" ,
RETAILTRANSACTIONTABLE.NETAMOUNT AS "Total" ,
RETAILTRANSACTIONINFOCODETRANS.INFOCODEID AS " Type " ,
RETAILTRANSACTIONINFOCODETRANS.INFORMATION,
MAX(CASE WHEN RETAILTRANSACTIONINFOCODETRANS.INFOCODEID = 'Phone Numb' THEN information END) AS phonenumber,
MAX(CASE WHEN RETAILTRANSACTIONINFOCODETRANS.INFOCODEID LIKE '%Any Commen%' THEN information END) AS comment
FROM
RETAILTRANSACTIONTABLE
INNER JOIN
RETAILTRANSACTIONINFOCODETRANS ON RETAILTRANSACTIONINFOCODETRANS.TRANSACTIONID = RETAILTRANSACTIONTABLE.TRANSACTIONID
INNER JOIN
RETAILTRANSACTIONSALESTRANS ON RETAILTRANSACTIONSALESTRANS.TRANSACTIONID = RETAILTRANSACTIONINFOCODETRANS.TRANSACTIONID
GROUP BY
GROUPING SETS ((RETAILTRANSACTIONINFOCODETRANS.TRANSDATE,
RETAILTRANSACTIONTABLE.RECEIPTID,
RETAILTRANSACTIONSALESTRANS.staff,
RETAILTRANSACTIONTABLE.NETAMOUNT,
RETAILTRANSACTIONINFOCODETRANS.INFORMATION,
RETAILTRANSACTIONINFOCODETRANS.INFOCODEID ),())
You can use conditional aggregation
select receiptid,
max(case when infotype='phone number' then information end) as phonenumber,
max(case when infotype like '%comment%' then information end) as comment
from tablename
group by receiptid
select * from
(
SELECT [receipt id]
,[infotype]
,[information]
FROM [test].[dbo].[report]) as x
pivot
(
max([information])
for [infotype] in([phone],[comment]) )as pvt

Pivot Multiple columns together in SQL

I've table like this
I need to get a result like this
RT Team PI Committed Done-Partial Done-Full
----------------------------------------------------------------
ART1 Team1 10 5 1 3
ART2 Team2 7 5 4 1
-----------------------------------------------------------------------
The way I tried is as follows
;with RecentPI as(
select * from (
select rt,Team,pi,[Finish Date],DENSE_RANK() over( partition by rt order by [Finish Date] desc) PIRank from Schedule_Manual S inner join TFS_ARTs_Teams T on T.ART=S.RT
group by RT,Team,PI,[Finish Date]
)tbl
where PIRank=1
)
select * from (select Obj.RT,Obj.[TFS Team], Obj.Type,Obj.PI,[PI Status] from Objectives Obj inner join RecentPI RP on RP.RT=Obj.RT and RP.Team=Obj.[TFS Team] and RP.PI=Obj.PI) as query
PIVOT (count(type) for [Type] in ([Committed])) p1
PIVOT (Count([PI Status]) for [pi status] in ([Done-Partial],[Done-Full])) p2
But it doesnt seems to be correct and also Im not getting full columns in the query. Sorry Im very beginner with SQL Pivot
You can Use this simple Query...your problem will be solved....
select RT,Team,[PI],
sum(case when [Type] = 'Committed' then 1 else 0 end) AS 'Committed',
sum(case when PIStatus = 'Done-Partial' then 1 else 0 end) AS 'Done-Partial',
sum(case when PIStatus = 'Done-Full' then 1 else 0 end) AS 'Done-Full'
from tbl_Pivot
group by RT,Team,[PI]
Output:-

SQL Count with multiple conditions then join

Quick one,
I have a table, with the following structure
id lid taken
1 1 0
1 1 0
1 1 1
1 1 1
1 2 1
Pretty simply so far right?
I need to query the taken/available from the lid of 1, which should return
taken available
2 2
I know I can simply do two counts and join them, but is there a more proficient way of doing this rather than two separate queries?
I was looking at the following type of format, but I can not for the life of me get it executed in SQL...
SELECT
COUNT(case taken=1) AS taken,
COUNT(case taken=0) AS available FROM table
WHERE
lid=1
Thank you SO much.
You can do this:
SELECT taken, COUNT(*) AS count
FROM table
WHERE lid = 1
GROUP BY taken
This will return two rows:
taken count
0 2
1 2
Each count corresponds to how many times that particular taken value was seen.
Your query is correct just needs juggling a bit:
SELECT
SUM(case taken WHEN 1 THEN 1 ELSE 0 END) AS taken,
SUM(case taken WHEN 1 THEN 0 ELSE 1 END) AS available FROM table
WHERE
lid=1
Alternatively you could do:
SELECT
SUM(taken) AS taken,
COUNT(id) - SUM(taken) AS available
FROM table
WHERE
lid=1
SELECT
SUM(case WHEN taken=1 THEN 1 ELSE 0 END) AS taken,
SUM(case WHEN taken=0 THEN 1 ELSE 0 END) AS available
FROM table
WHERE lid=1
Weird application of CTE's:
WITH lid AS (
SELECT DISTINCT lid FROM taken
)
, tak AS (
SELECT lid,taken , COUNT(*) AS cnt
FROM taken t0
GROUP BY lid,taken
)
SELECT l.lid
, COALESCE(a0.cnt, 0) AS available
, COALESCE(a1.cnt, 0) AS taken
FROM lid l
LEFT JOIN tak a0 ON a0.lid=l.lid AND a0.taken = 0
LEFT JOIN tak a1 ON a1.lid=l.lid AND a1.taken = 1
WHERE l.lid=1
;