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.
Related
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
I am a new SQL developer and I am trying to write a query that will retrieve the following results from three tables in the database:
ID Text Score #1 Score #2 Score #3
The schema for the three tables are:
T_TextScore Table: Id, TextId, Label, Score, TypeId
T_Text: Id, Text
T_Status Table: Id, Type
The T_TextScore table contains three different types of scroes for each text. I was able to retrieve the scores for all texts but I am still unable to show each type of score for each text in one row as illustrated above. So could you please tell me how I can get the desired result?
Here's the query I have and I think it is not efficient in terms of performance as well:
SELECT T_TextScore.TextId, T_Text.Text, T_TextScore.Label, T_TextScore.Score
FROM T_TextScore INNER JOIN
T_Text ON T_TextScore.TextId = T_Text.Id
WHERE (T_TextScore.TypeId = 3)
UNION
SELECT T_TextScore.TextId, T_Text.Text, T_TextScore.Label, T_TextScore.Score
FROM T_TextScore INNER JOIN
T_Text ON T_TextScore.TextId = T_Text.Id
WHERE (T_TextScore.TypeId = 4)
UNION
SELECT T_TextScore.TextId, T_Text.Text, T_TextScore.Label, T_TextScore.Score
FROM T_TextScore INNER JOIN
T_Text ON T_TextScore.TextId = T_Text.Id
WHERE (T_TextScore.TypeId = 5);
UPDATE:
After using the query suggested by #Craig Young, I got two rows for each text and I don't know why. Could you please explain to me why?
enter image description here
You want conditional aggregation. My best guess is simply:
SELECT ts.TextId,
MAX(CASE WHEN ts.TypeId = 3 THEN ts.Score END) as Score_1,
MAX(CASE WHEN ts.TypeId = 4 THEN ts.Score END) as Score_2,
MAX(CASE WHEN ts.TypeId = 5 THEN ts.Score END) as Score_3
FROM T_TextScore ts
GROUP BY ts.TextId;
Your query isn't doing quite what you asked for. The following would be a much better way of doing what you're currently doing:
SELECT ts.TextId, t.Text, ts.Label, ts.Score
FROM T_TextScore ts /* Table alias makes query much more readable */
INNER JOIN T_Text t ON
ts.TextId = t.Id
WHERE ts.TypeId IN (3, 4, 5)
However, the first part of your question suggests you actually want to pivot your data?
If so you can use PIVOT syntax. Or manual pivoting:
SELECT ts.TextId,
/* Use aggregate function to get only 1 per TextId */
MAX(t.Text) AS Text, MAX((ts.Label) AS Label,
/* Simply move ts.Score to the correct column to be summed. */
SUM(CASE WHEN ts.TypeId = 3 THEN ts.Score ELSE 0 END) AS Score3,
SUM(CASE WHEN ts.TypeId = 4 THEN ts.Score ELSE 0 END) AS Score4,
SUM(CASE WHEN ts.TypeId = 5 THEN ts.Score ELSE 0 END) AS Score5
FROM T_TextScore ts
INNER JOIN T_Text t ON
ts.TextId = t.Id
WHERE ts.TypeId IN (3, 4, 5)
GROUP BY ts.TextId
NOTE: PIVOT syntax is a little more succinct. But strangely I have seen it run slightly slower than manual pivot on occasion. So if performance is important, you'll have to benchmark.
Based on your comment:
After using the query suggested by #Craig Young, I got two rows for each text and I don't know why.
You probably either removed the GROUP BY clause, or included Text and Label in the GROUP BY. This made me realise that I'd forgotten to deal with these 2 columns which weren't part of either aggregate or GROUP BY.
I've updated my query above appropriately. However, I should point out lack of sample data makes it tricky to determine exactly what you're trying to achieve - particularly with the Label column which could be different per Score Type.
I need to create a general report about of a trucks in a company.
I have this tables in my schema:
Schema image:
Basically, I need to create a table containing the following:
|Location|Trucks|TotalOfCampaings|CampaingsWithCompleteStatus|CampaingsWithInProcessStatus|
Location: Location of the trucks, are in the Truck table.
Trucks: Number of Trucks by Location.
TotalOfCampaings: Total Number of Campaings by the Location and Trucks.
CampaingsWithCompleteStatus: Total Number of Campaings Completed, the status are in the table Campaing Control.
CampaingsWithInProcessStatus: Total Number of Campaings not finished.
Campaing = Order to fix one or multiple trucks.
I tried with a inner joins querys, but i cant get what i expect for the general report.
I would appreciate help me with this!
SELECT *
FROM
-- Prepare the base data for the report
(SELECT location, COUNT(*) AS Trucks FROM Truck GROUP BY location) loc
-- The statistics needed, make sure it is 1 to 1
-- The status value just guess as you did not mention in the question
OUTER APPLY
(
SELECT
COUNT(*) AS TotalOfCampaings,
SUM(CASE WHEN cc.campaing_status = 'Complete' THEN 1 ELSE 0 END) AS CampaingsWithCompleteStatus,
SUM(CASE WHEN cc.campaing_status = 'InProcess' THEN 1 ELSE 0 END) AS CampaingsWithInProcessStatus
FROM CampaingControl cc INNER JOIN Truck t ON cc.vin = t.vin
WHERE t.location = loc.location
) stat
I'm having trouble counting two things in an SQL query. I need to pull a list of files that have been accessed at least five times each by employees from both marketing and sales. I know I'm using COUNT incorrectly but I don't know how. Here's my query so far:
SELECT FileId
FROM Files
JOIN FileAccesses ON Files.FileId = FileAccesses.FileId
WHERE Count(AccessUserGroup=1)>5 AND Count(AccessUserGroup=2)>5
It produces the error
Incorrect syntax near ')'.
Files is a table with the int FileId as its primary key. FileAccesses stores FileId values from Files but not as the primary key. It keeps track of a bunch of metadata every time a user touches a file. For the purposes of this question, the part that matters is AccessUserGroup, a tinyint that is set to 1 for marketing and 2 for sales.
This is the query that you want:
SELECT fa.FileId
FROM FileAccesses fa
GROUP BY fa.FileId
HAVING SUM(CASE WHEN AccessUserGroup = 1 THEN 1 ELSE 0 END) > 5 AND
SUM(CASE WHEN AccessUserGroup = 2 THEN 1 ELSE 0 END) > 5;
Notes:
You don't need theJOIN, unless your FileAccesses could have a file id not in Files (which I consider unlikely).
You should be using GROUP BY if you want to use aggregation functions.
The comparisons go in the HAVING clause.
The COUNT() with an expression produces an error in SQL Server (it works in some other databases). SUM() with CASE does the conditional aggregation.
I guess you'll need the actual file info as well not just the file id, so you can use a cte (common table expression) https://msdn.microsoft.com/en-us/library/ms175972.aspx
;WITH cte AS (
SELECT FileAccesses.FileId FROM FileAccesses
GROUP BY FileId
HAVING COUNT(CASE AccessUserGroup WHEN 1 THEN 1 ELSE NULL END) > 5
AND COUNT(CASE AccessUserGroup WHEN 2 THEN 1 ELSE NULL END) > 5
)
SELECT * FROM File
INNER JOIN cte ON File.FileId = cte.FileId
I am trying to write a query that brings up the details (invoiceNumber, name, phone & email) from a table but only where the entries match these specific requirements:
Return the rows where the email address appears only once in the whole table from any date
AND
Return the rows where the email address multiple times WHERE the email has only been entered ONCE within the last 3 months.
I am fairly sure that this requires nested statements but I have no idea how to go about setting it up.
Any help would be greatly appreciated!
Approach this by thinking about the email addresses. You can determine the frequency of appearance by doing a group by:
select emailaddress, count(*) as TotalCnt,
sum(case when invoicedate >= sysdate - 90 then 1 else 0 end) as LastThreeMonths
from t
group by emailaddress;
This gives you the information you need. The following query joins this back to the original table to get the rows you are looking for:
select t.*
from t join
(select emailaddress, count(*) as TotalCnt,
sum(case when invoicedate >= sysdate - 90 then 1 else 0 end) as LastThreeMonths
from t
group by emailaddress
) e
on t.emailaddress = e.emailaddress
where e.TotalCnt = 1 or e.LastThreeMonths = 1