Pivoting and merging data from a sql query - sql

This is My Query:
SELECT ad.Name, av.Value AS Attribute1, ctv.Value AS Attribute2
FROM AttributeDefinitions AS ad WITH (nolock)
INNER JOIN AttributeValues AS av WITH (nolock)
ON ad.AttributeDefinitionID = av.AttributeDefinitionID
INNER JOIN AttributeCategories
ON ad.AttributeCategoryID = AttributeCategories.AttributeCategoryID
LEFT OUTER JOIN CodeTableValues AS ctv WITH (nolock)
ON av.CodeTableValueID = ctv.CodeTableValueID
WHERE (AttributeCategories.Name = 'Camp') AND (av.AttributeValueGroupID = 9840)
My Result Looks Like This:
Name Attribute1 Attribute2
Childs Age: 10
Attended Camp Before?: Yes
Childs T-Shirt Size: large NULL
Allergies Description none NULL
Phone # 212-555-1212 NULL
Pickup Mary Jordan NULL
Name= Name of Attribute Column
Attribute1 = Data is from a free Form
Attribute2 = Data is from a Drop down Menu
What I would like to do is Rotate the data so that the information from column “Name” becomes the column header and I need to combine the values from attribute 1 & 2
This is what my Result Should Look Like:
*Childs Age Attended Camp Before? Childs T-Shirt Size Allergies Description Phone# Pickup*
10 yes large none 212-555-1212 Mary Jordan

In Oracle DB I am using CASE statement to convert rows into columns.
Take a look on this example:
select event_date
,sum(case when service_type = 'OCSAC_DEG' then service_count end) ocsac_deg
,sum(case when service_type = 'SMS_ONL' then service_count end) sms_onl
,sum(case when service_type = 'SMS_DEG' then service_count end) sms_deg
,sum(case when service_type = 'DATA_ONL' then service_count end) data_onl
,sum(case when service_type = 'DATA_DEG' then service_count end) data_deg
from STATS
where to_char(event_date, 'yyyymm') = to_char(add_months(sysdate,-1), 'yyyymm')
group by event_date
order by event_date desc

Related

Creating SQL values from two columns using the selective aggregate of each column

I have the following four tables:
region_reference, community_grants, HealthWorkers and currency_exchange
and the follow SQL query which works:
SELECT HealthWorkers.worker_id
, community_grants.percentage_price_adjustment
, community_grants.payment_status
, community_grants.chosen
, (region_reference.base_price * currency_exchange.euro_value) AS price
FROM currency_exchange
INNER JOIN (
region_reference INNER JOIN (
HealthWorkers INNER JOIN community_grants
ON HealthWorkers.worker_id = community_grants.worker_id
) ON (
region_reference.community_id = community_grants.community_id
) AND (region_reference.region_id = community_grants.region_id)
)
ON currency_exchange.currency = HealthWorkers.preferred_currency
WHERE (
HealthWorkers.worker_id="malawi_01"
AND community_grants.chosen=True
);
It gives me the following result set:
However, my task is to create an entity that includes just 4 values.
type OverallPriceSummary struct {
Worker_id string `json:"worker_id"`
Total_paid decimal.Decimal `json:"total_paid"`
Total_pledged decimal.Decimal `json:"total_pledged"`
Total_outstanding decimal.Decimal `json:"total_outstanding"`
}
Total_paid is the sum of values for the specified worker_id where payment_status = “1” (combined for all records)
Total_outstanding is the sum of values where payment_status is “0” and chosen is true (combined for all records)
Total_pledged is the sum of Total_paid and Total_outstanding (also combined for all records)
I currently obtain these values by aggregating this manually in my code as postgresql iterates through the resultset but I believe there is a way to avoid this interim SQL query and get what I need from a single SQL query.
I suspect it involves the use of SUM AS and inner queries but I don’t know how to bring it all together. Any help or direction would be much appreciated.
EDIT:
I have provided some sample data below:
region_reference
region_id
region_name
base_price
community_id
1
Lilongwe
100
19
2
Mzuzu
50
19
HealthWorkers
worker_id
worker_name
preferred_currency
billing_address
charity_logo
malawi_01
Raphael Salanga
EUR
Nkhunga Health Centre in Nkhotakota District
12345
community_grants
region_id
campaign_id
worker_id
percentage_price_adjustment
community_id
payment_status
chosen
paid_price
1
1
malawi_01
10
19
0
Yes
0
2
1
malawi_01
0
19
1
Yes
20
3
1
malawi_01
1
19
0
Yes
0
1
1
malawi_01
0
23
0
Yes
30
currency_exchange
currency
currency_symbol
euro_value
EUR
€
1
USD
$
0.84
Consider conditional aggregation using Postgres' FILTER clause where you pivot data to calculated conditional columns.
Below assumes sum of values is the sum of calculated price expressed as: region_reference.base_price * currency_exchange.euro_value. Adjust as needed.
SELECT h.worker_id
, SUM(r.base_price * ce.euro_value) FILTER(WHERE
cg.payment_status = 1
) AS total_paid
, SUM(r.base_price * ce.euro_value) FILTER(WHERE
cg.payment_status = 0 AND
cg.chosen=True
) AS total_outstanding
, SUM(r.base_price * ce.euro_value) FILTER(WHERE
(cg.payment_status = 1) OR
(cg.payment_status = 0 AND cg.chosen=True)
) AS total_pledged
FROM community_grants cg
INNER JOIN region_reference r
ON r.community_id = cg.community_id
AND r.region_id = cg.region_id
INNER JOIN HealthWorkers h
ON h.worker_id = cg.worker_id
AND h.worker_id = 'malawi_01'
INNER JOIN currency_exchange ce
ON ce.currency = h.preferred_currency
GROUP BY h.worker_id
Try something like:
SELECT
worker_id
,sum(case when payment_status = “1”
then paid_price else 0 end) as Total_paid
,sum(case when payment_status = “0” and chosen = true
then paid_price else 0 end) as Total_outstanding
,sum(case when (payment_status = “1”)
or (payment_status = “0” and chosen = true)
then paid_price else 0 end) as Total_pledged
from community_grants
group by worker_id

Selecting multiple rows of a column in a SQL Server query

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

Oracle SQL combine 2 queries from same table with output in 2 different columns

I'm using an Oracle SQL database.
I'm trying to combine this 2 queries into one from same table:
select count(CustomerID) from Customers
where (City = 'Berlin' or City = 'London')
from Customers;
select count(CustomerID) from Customers
where (City = 'Mannheim' or City = 'Strasbourg')
from Customers;
And my output would like to be something like exported on 2 columns:
| Berlin & London | Mannheim & Strasbourg |
|-----------------------------------------|
| 5 | 10 |
example of db here, https://www.w3schools.com/sql/trysql.asp?filename=trysql_op_in
I think the answer will be:
(select count(CustomerID) from Customers
where (City = 'Berlin' or City = 'London'))
union
(select count(CustomerID) from Customers
where (City = 'Marseille' or City = 'Tsawassen'));
union
(select count(CustomerID) from Customers
where (City = 'Strasbourg' or City = 'Madrid'));
Still testing...
Finally got the job done by using this case.
Thanks to everyone involved !
SELECT
COUNT(CASE
WHEN work_zone = 'AMBGI01' OR
work_zone = 'AMBGI02' OR
work_zone = 'AMBGI03' AND
task_type = 'P' THEN work_zone
END) "HighBay Putaways",
COUNT(CASE
WHEN work_zone = 'AMBGI04' OR
work_zone = 'AMBGI05' OR
work_zone = 'AMBGI06' OR
work_zone = 'AMBGI07' AND
task_type = 'P' THEN work_zone
END) "LowBay Putaways",
COUNT(CASE
WHEN from_loc_id = 'THEWALL' AND
task_type = 'P' THEN from_loc_id
END) "THE WALL",
COUNT(CASE
WHEN tag_id like '%' AND
from_loc_id like 'EXPANS%' AND
task_type = 'P' THEN tag_id
END) "EXPANSION",
COUNT(CASE
WHEN final_loc_id like '_______' AND
(status = 'In Progress' OR
status = 'Released') AND
task_type = 'R' THEN final_loc_id
END) "Replens"
FROM move_task;
Easiest way is the following:
select count(CASE WHEN City = 'Berlin' or City = 'London' THEN City END) "Berlin & London"
, count(CASE WHEN City = 'Mannheim' or City = 'Strasbourg' THEN City END) "Mannheim & Strasbourg"
from Customers
Its not clear if you have two tables (customers, country) or one. If there are two you need to show us structure. w3schools.com says there is no such table like country and customers does not contain store column. Anyway you need conditional count, something like here:
select count(case when city in ('Berlin', 'London')
then 1 end) as "Berlin & London",
count(case when city in ('Mannheim', 'Strasbourg')
then 1 end) as "Mannheim & Strasbourg"
from Customers
where city in ('Berlin', 'London', 'Mannheim', 'Strasbourg')
You could also use pivot, but this is simpler, more readable and works in older Oracle versions.

Joining two SQL queries with different variations of data

I have this query which returns some data:
select
id, name, username, email, password,
first_name, last_name, usertype,
block, sendemail, registerDate, lastvisitDate,
activation, params, uuid
from
jml2_users
where
uuid in ('51840915-e570-430d-9911-7247d076f6e7', '51912193-6694-4ca5-94c9-9f31d076f6e7',
'51927ada-6370-4433-8a06-30d2d076f6e7', '51c05ad7-d1d0-4eb6-bc6b-424bd076f6e7',
'd047adf1-a6af-891e-94a2d0b225dcd1b6', '2aba38f2-d7a7-0a7a-eff2be3440e3b763')
and the other query is this
SELECT
ct.TrainingID, ct.UserID, ct.TrainingType, ct.TrainingStatus,
ct.TrainingScore, ct.TrainingDate,
dbo.fn_StripCharacters(ctt.product_type,'^a-z0-9') as product_type,
ctt.product_type as oldName
FROM
clientTraining as ct
INNER JOIN
clientTraningTypes as ctt ON ct.TrainingType = ctt.TypeID
WHERE
1=1
AND UserID IN ('51840915-e570-430d-9911-7247d076f6e7', '51927ada-6370-4433-‌​8a06-30d2d076f6e7')
AND TrainingType IN (SELECT TypeID
FROM complaincetestlinks
WHERE parent_client_id = 1039
AND isactive = 1 AND isdeleted = 0)
Both queries return different results, with userid and uuid in both tables have same data, I mean we can do a join, but the problem is: I want the second query data which are rows should be converted to columns in the new query and the data should be copied to new query with a join to the second query based on userid and uuid
I am noob at SQL and first question comes to me how do I convert the first query row data to columns and populate it with data because the first query has 5 rows. So eventually I need 5*4 = 20 columns for the new query and the data to be passed and uploaded to the new query from the second query
Not sure what I need to do here, I am lost
Here is an example of how to pivot the supplied query on product_type. I've only done some of the columns. Hopefully you can follow the example to add more.
SELECT
TrainingID,
UserID,
TrainingType,
TrainingStatus,
MAX(CASE
WHEN product_type = 'MarketLinkedCDs' THEN TrainingDate ELSE NULL
END) TrainingDate_MarketLinkedCDs,
MAX(CASE
WHEN product_type = 'StructuredNotes' THEN TrainingDate ELSE NULL
END) TrainingDate_StructuredNotes,
MAX(CASE
WHEN product_type = 'BufferedRangeAccrualNotes' THEN TrainingDate ELSE NULL
END) TrainingDate_BufferedRangeAccrualNotes,
MAX(CASE
WHEN product_type = 'MarketLinkedCDs' THEN TrainingScore ELSE NULL
END) TrainingScore_MarketLinkedCDs,
MAX(CASE
WHEN product_type = 'StructuredNotes' THEN TrainingScore ELSE NULL
END) TrainingScore_StructuredNotes,
MAX(CASE
WHEN product_type = 'BufferedRangeAccrualNotes' THEN TrainingScore ELSE NULL
END) TrainingScore_BufferedRangeAccrualNotes
FROM
(
SELECT ct.TrainingID, ct.UserID, ct.TrainingType, ct.TrainingStatus,
ct.TrainingScore,
ct.TrainingDate, dbo.fn_StripCharacters(ctt.product_type,'^a-z0-9') as product_type,
ctt.product_type as oldName FROM clientTraining as ct INNER JOIN
clientTraningTypes as ctt ON ct.TrainingType = ctt.TypeID WHERE 1=1 and
UserID in ('51840915-e570-430d-9911-7247d076f6e7',
'51927ada-6370-4433-‌​8a06-30d2d076f6e7')
and TrainingType IN (select TypeID from complaincetestlinks where
parent_client_id = 1039 and isactive = 1 and isdeleted = 0)
) F
GROUP BY
TrainingID,
UserID,
TrainingType,
TrainingStatus,

SQL Aggreate Functions

I have table which list a number of cases and assigned primary and secondary technicians. What I am trying to accomplish is to aggregate the number of cases a technician has worked as a primary and secondary tech. Should look something like this...
Technician Primary Secondary
John 4 3
Stacy 3 1
Michael 5 3
The table that I am pulling that data from looks like this:
CaseID, PrimaryTech, SecondaryTech, DOS
In the past I have used something like this, but now my superiors are asking for the number of secondary cases as well...
SELECT PrimaryTech, COUNT(CaseID) as Total
GROUP BY PrimaryTech
I've done a bit of searching, but cant seem to find the answer to my problem.
Select Tech,
sum(case when IsPrimary = 1 then 1 else 0 end) as PrimaryCount,
sum(case when IsPrimary = 0 then 1 else 0 end) as SecondaryCount
from
(
SELECT SecondaryTech as Tech, 0 as IsPrimary
FROM your_table
union all
SELECT PrimaryTech as Tech, 1 as IsPrimary
FROM your_table
) x
GROUP BY Tech
You can group two subqueries together with a FULL JOIN as demonstrated in this SQLFiddle.
SELECT Technician = COALESCE(pri.Technician, sec.Technician)
, PrimaryTech
, SecondaryTech
FROM
(SELECT Technician = PrimaryTech
, PrimaryTech = COUNT(*)
FROM Cases
WHERE PrimaryTech IS NOT NULL
GROUP BY PrimaryTech) pri
FULL JOIN
(SELECT Technician = SecondaryTech
, SecondaryTech = COUNT(*)
FROM Cases
WHERE SecondaryTech IS NOT NULL
GROUP BY SecondaryTech) sec
ON pri.Technician = sec.Technician
ORDER By Technician;
SELECT COALESCE(A.NAME, B.NAME) AS NAME, CASE WHEN A.CASES IS NOT NULL THEN A.CASES ELSE 0 END AS PRIMARY_CASES,
CASE WHEN B.CASES IS NOT NULL THEN B.CASES ELSE 0 END AS SECONDARY_CASES
FROM
(
SELECT COUNT(*) AS CASES, PRIMARYTECH AS NAME FROM YOUR_TABLE
GROUP BY PRIMARYTECH
) AS A
FULL OUTER JOIN
(
SELECT COUNT(*) AS CASES, SECONDARYTECH AS NAME FROM YOUR_TABLE
GROUP BY SECONDARYTECH
) AS B
ON A.NAME = B.NAME