I'm fairly new to Oracle SQL and have been tasked with creating a crosstab report using SQL. I have a single source table with a simple structure similar to this:
I'm trying to crosstab the results to show the total staff per state as follows:
Ideally I'd like to dynamically cater for offices opening in new states.
I've been looking into PIVOTS but can't seem to get my head around it. Any guidance would be gratefully received.
Thank you.
In a PIVOT you can start from a source sub-query.
Then you define what field to aggregate for which titles in another field.
SELECT *
FROM
(
SELECT Company, State, Staff
FROM YourCompanyStaffTable
WHERE State IN ('Illinois', 'Texas', 'Tennessee', 'Missouri', 'Kansas', 'Indiana')
) src
PIVOT (
SUM(Staff)
FOR State IN (
'Illinois' as Illinois,
'Texas' as Texas,
'Tennessee' as Tennessee,
'Missouri' as Missouri,
'Kansas' as Kansas,
'Indiana' as Indiana
)
) pvt
ORDER BY Company
In this query, the new column names are generated from the "State" column.
Note that in the source query there's also a limit on those names.
That's just for efficiency reasons. (less data to pull from the table)
And it'll group the results by the source fields that aren't used in the PIVOT declaration.
In this case it automatically groups on the "Company" column.
So it sums the total "Staff" for each "State" per "Company".
use case when
select company, sum(case when state='Illinois' then staff else 0 end) as Illinois,
sum(case when state='Texas' then staff else 0 end) as Texas,
sum(case when state='Tennessee' then staff else 0 end) as Tennessee,
sum(case when state='Missouri' then staff else 0 end) as Missouri,
sum(case when state='Kansas' then staff else 0 end) as kansas,
sum(case when state='Indiana' then staff else 0 end) as Indiana from t
group by company
Related
I want to produce a report that lists all the observation dates and, for each date, lists the total number of people fully vaccinated in each one of the 4 countries used in this assignment.
people_fully_vaccinated needs to be inner join with location
the first image is the format required.
the second image contains the data:
you can use:
select date,
sum(case when country = 'country 1' then vacinated_count else 0 end) as country1count,
sum(case when country = 'country 2' then vacinated_count else 0 end) as country2count,
...
...
from table
group by date
considering you have vaciniated people count ready for each country in a table.
I'm trying to get table with 3 columns: 1- year, 2- quantity of foreign cars, 3- quantity of Russian cars (grouped by year). Values from the table having columns: 1- year, 2- type, 3- id application.
Result is always the same - one of the column with quantity is 0 or both of columns has the same values, another words, it is wrong . Where is the mistake?
Result source table
I was trying different ways:
SELECT autotable.year as Year,
count(CASE WHEN autotable.Type='Foreign' THEN 1 ELSE null END) as Quantity_Foreign_Cars,
count(CASE WHEN autotable.Type= 'Russia' THEN 1 ELSE null END) as Quantity_Russian_Cars
FROM banktest.autotable
group by autotable.Year;
SELECT autotable.year as Year,
sum(IF (autotable.Type='Foreign',1,0)) as Foreign_Cars,
sum(IF (autotable.Type ='Russia',1,0)) as Russian_Cars
FROM banktest.autotable
group by autotable.Year;
SELECT autotable.year as Year,
(SELECT count(autotable.Type)
FROM banktest.autotable
where autotable.Type='Foreign') as Foreign_Cars,
(SELECT count(autotable.Type)
FROM banktest.autotable
having autotable.Type='Russia') as Russian_Cars
FROM banktest.autotable
group by autotable.Year;
So as far as i understand, you are having a table with 2 columns. Year and Type, right?
You need to group by both of your columns and use the count method.
If you are using a oracle database this should do the trick:
select count(*), trunc(year,'Y'), type
from autotable
group by
trunc(year,'Y'), type;
This will do what you want:
select count(case when type = 'Foreign' then 1 end) as foreign, count(case
when type = 'Russia' then 1 end) as russian, trunc(year,'Y')
from autotable
group by
trunc(year,'Y')
I have a table in PostgreSQL that contains demographic data for each province of my country.
Columns are: Province_name, professions, Number_of_people.
As you can see, Province_names are repeated for each profession.
How then can I get the province names not repeated and instead get the professions in separate columns?
It sounds like you want to pivot your table (Really: It is better to show data and expected output in your question!)
demo:db<>fiddle
This is the PostgreSQL way (since 9.4) to do that using the FILTER clause
SELECT
province,
SUM(people) FILTER (WHERE profession = 'teacher') AS teacher,
SUM(people) FILTER (WHERE profession = 'banker') AS banker,
SUM(people) FILTER (WHERE profession = 'supervillian') AS supervillian
FROM mytable
GROUP BY province
If you want to go a more common way, you can use the CASE clause
SELECT
province,
SUM(CASE WHEN profession = 'teacher' THEN people ELSE 0 END) AS teacher,
SUM(CASE WHEN profession = 'banker' THEN people ELSE 0 END) AS banker,
SUM(CASE WHEN profession = 'supervillian' THEN people ELSE 0 END) AS supervillian
FROM mytable
GROUP BY province
What you want to do is a pivot which is a little more complicated in Postgresql then in other rdbms. You can use the crosstab function. Find a introduction here: https://www.vertabelo.com/blog/technical-articles/creating-pivot-tables-in-postgresql-using-the-crosstab-function
for you it would look something like this:
SELECT *
FROM crosstab( 'select Province_name, professions, Number_of_people from table1 order by 1,2')
AS final_result(Province_name TEXT, data_scientist NUMERIC,data_engineer NUMERIC,data_architect NUMERIC,student NUMERIC);
I have 51 tables (in a single DB) having same column and schema for 51 USA states. All i have to do is to run the same query for all 51 tables. The result of each state should return in to new table with a tableformat like this.
Eg. Table name : TX_EED
New Table name :TX_EED_v0
Following is the query which i will run for each state:
Select distinct a.Geoid, Lat, Long, StateCode, CountyCode, PostalCode,StrVal_SFD ,StrVal_MFD,StrVal_MH from EED2013..TX_EED a
inner join
(Select Geoid,
SUM(case when LOBNAME ='SFD'THEN CvgAval_MinThresh else 0 end) as StrVal_SFD,
SUM(case when LOBNAME ='MFD'THEN CvgAval_MinThresh else 0 end) as StrVal_MFD,
SUM(case when LOBNAME ='MH'THEN CvgAval_MinThresh else 0 end) as StrVal_MH
FROM EED2013..TX_EED group by Geoid) b
on a.Geoid =b.Geoid-------7,473,869
If you have 51 tables with the same schema, then you should really have a single table. By the way, there are more than "51" state-equivalents in the US -- DC, Puerto Rico, Guam, US Virgin Islands, and various military addresses count as "states" according to the US Post Office (and I think the US Census).
In any case, create a view:
create view v_AllStates as
select ak.*
from data_al union all
select al.*
from data_al union all
. . .
select wy.*
from data_wy;
You can then use this view in your queries, presumably simplifying your life.
SELECT Projects.Projectid, Projects.ProjectNumber, Projects.ProjectName,
Projects.ProjectBudgetedIS, Projects.ProjectSpentIS,
Projects.ProjectBudgetedBusiness, Projects.PorjectSpentBusiness, Project.Status,
ProjectStatus.Status AS Expr1
FROM Projects
INNER JOIN ProjectStatus ON Projects.Status = ProjectStatus.StatusID
WHERE Projects.Status = #Status
So what I want to do is take the sum of a table called invoices which has a field called ISorBusiness and a field called totalspent and store that data into the projects tabel in the appropriate field. So that when I get an invoice that is charged to the IS it takes that amount and rolls it into the Projects.ProjectSpentIS and if I get a invoice that is to the business it rolls it into the Projects.ProjectBudgetedBusiness.
I know this should be easy and sorry for the noobish question. Thanks in advance!
I would do something like:
SELECT SUM(CASE WHEN (IsOrBusiness = 'IS') THEN totalSpent ELSE 0 END) AS IsSpent,
SUM(CASE WHEN (IsOrBusiness = 'Business') THEN totalSpent ELSE 0 END) AS BusinessSpent
FROM Invoices
Obviously the usage depends on whether you are trying to write an insert query or select this data as part of the select query you have posted.