Perform calculation without having to do it manually for each column? - sql

I have the following view set up in SQL Server:
VIEW
(left table: population data per year; middle table: municipalities; right table: municipality areas in km²)
Query
SELECT
dbo.T_GEMEINDE.GKZ, dbo.T_GEMEINDE.NAME,
dbo.T_BASE_DAUERSIEDLUNGSRAUM_GEMEINDE.FLAECHE_KM2 / dbo.T_BASE_DAUERSIEDLUNGSRAUM_GEMEINDE.DAUERSIEDLUNGSRAUM_KM2 AS [ges. Fläche / Dauersiedlungsr.],
dbo.T_BASE_GEMEINDE_BEVOELKERUNG_JAHR_BEGINN.J2017 / dbo.T_BASE_DAUERSIEDLUNGSRAUM_GEMEINDE.FLAECHE_KM2 AS [ges. Bevölkerungsdichte],
dbo.T_BASE_GEMEINDE_BEVOELKERUNG_JAHR_BEGINN.J2017 / dbo.T_BASE_DAUERSIEDLUNGSRAUM_GEMEINDE.DAUERSIEDLUNGSRAUM_KM2 AS [Bevölkerungsdichte Dauersiedlungsraum]
FROM
dbo.T_BASE_DAUERSIEDLUNGSRAUM_GEMEINDE
INNER JOIN
dbo.T_GEMEINDE ON dbo.T_BASE_DAUERSIEDLUNGSRAUM_GEMEINDE.GKZ = dbo.T_GEMEINDE.GKZ
INNER JOIN
dbo.T_BASE_GEMEINDE_BEVOELKERUNG_JAHR_BEGINN ON dbo.T_GEMEINDE.GKZ = dbo.T_BASE_GEMEINDE_BEVOELKERUNG_JAHR_BEGINN.GKZ
The last column in the view contains a calculation (population density for 132 municipalities for a certain year) for the year 2017 and uses the column J2017 from the table seen on the left. This is the output (Bevölkerungsdichte Dauersiedlungsraum):
Current output:
OUTPUT
Desired output:
The rightmost column (Bevölkerungsdichte Dauersiedlungsraum) seen in the provided output screenshot has the output data of the calculation for the year 2017. The same output has to be generated for all the other years, but each as a separate column.
Question: how do I perform the calculation which you can see in the last column in the view for all years (J2017-J2050) without having to do it manually for each year column?
Thanks in advance.

if you want someone to provide you with a complete solution then you will need to supply:
CREATE TABLE statements for the 3 tables
INSERT INTO... statements to provide sample data for all 3 tables
However, if you just want a suggestion about how to approach this problem then I would use an UNPIVOT statement to create a view/table that
holds all the columns in dbo.T_BASE_GEMEINDE_BEVOELKERUNG_JAHR_BEGINN
apart from the "year" columns (J2017, J2018, j2019, ...)
adds a single "year" column with values from 2017 to 2050
adds a single value column to hold the population for each year
By joining your existing tables to this new table/view and grouping by your new "year" column you should achieve what you want

Related

Qlik - Building a dynamic view

I have a SQL query that creates a table, and every month 2 new columns will be added for that table related to the current month.
I have tried without success to set up a flat table (visual) in Qlik that will automatically expand every month to include these table. Is there a way to do this, and i so please point me in the right direction.
You can have a look at CrossTable prefix.
This prefix allows a wide table to be converted to a long table.
So if we have data like this:
After running the following script:
CrossTable:
CrossTable(Month, Sales)
LOAD Item,
[2022-10],
[2022-11],
[2022-12],
[2023-01],
[2023-02],
[2023-03],
[2023-04]
FROM
[C:\Users\User1\Documents\SO_75447715.xlsx]
(ooxml, embedded labels, table is Sheet1);
The final data will looks like below. As you can see there are only 3 columns. All xls month columns (after Item) are now collapsed under one field - Month and all the values are collapsed under Sales column.
Having the data in this format then allows creating "normal" charts with adding Month column as dimension and use sum(Sales) as an expression.
P.S. If you dont want to manage the new columns being added then the script can be:
CrossTable(Month, Sales)
LOAD
Item,
*
FROM
...

Select tables in database and group them by partial name

I have a database that gets new tables automatically added to it via create table if not exists statements.
The table names are in the following format:
somenamebasedondatasource_YEAR_period_X
Where X is a financial period of the business year, being a number 1-13.
Is there a query I can run against the schema table to get all the tables in the database then group them by the year contained in the name of the table.
So if my current tables list looks like this:
somenamebasedondatasource_2018_period_1
somenamebasedondatasource_2018_period_2
somenamebasedondatasource_2018_period_3
somenamebasedondatasource_2018_period_4
somenamebasedondatasource_2018_period_5
somenamebasedondatasource_2018_period_6
somenamebasedondatasource_2018_period_7
somenamebasedondatasource_2019_period_8
somenamebasedondatasource_2019_period_9
somenamebasedondatasource_2019_period_10
somenamebasedondatasource_2019_period_11
somenamebasedondatasource_2019_period_12
somenamebasedondatasource_2019_period_13
somenamebasedondatasource_2018_period_1
somenamebasedondatasource_2019_period_2
somenamebasedondatasource_2019_period_3
somenamebasedondatasource_2019_period_4
somenamebasedondatasource_2019_period_5
somenamebasedondatasource_2019_period_6
somenamebasedondatasource_2019_period_7
someothernamedatasourcesource_2018_period_1
someothernamedatasourcesource_2018_period_2
someothernamedatasourcesource_2018_period_3
someothernamedatasourcesource_2018_period_4
someothernamedatasourcesource_2018_period_5
someothernamedatasourcesource_2018_period_6
someothernamedatasourcesource_2018_period_7
someothernamedatasourcesource_2019_period_8
someothernamedatasourcesource_2019_period_9
someothernamedatasourcesource_2019_period_10
someothernamedatasourcesource_2019_period_11
someothernamedatasourcesource_2019_period_12
someothernamedatasourcesource_2019_period_13
someothernamedatasourcesource_2018_period_1
someothernamedatasourcesource_2019_period_2
someothernamedatasourcesource_2019_period_3
someothernamedatasourcesource_2019_period_4
someothernamedatasourcesource_2019_period_5
someothernamedatasourcesource_2019_period_6
someothernamedatasourcesource_2019_period_7
I would like an output that lists:
2018
2019
Then when the list of tables gets bigger into 2020 and beyond, it lists any years for those tables too like
2018
2019
2020
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = database_name
/*not sure what else goes here.
After that I also want to do the same thing again for the period_X but only for a certain year. (so after a user selects the year from the first query, I want to show them the periods for that year from the result of the second query.)
PS: I can change the naming convention for the tables if that makes this easier, it's all just test data at this point. Each table does contain the year and period in a column in each of it's rows, I was only splitting them up to try to avoid big long select queries when grabbing the data for later use. (the tables contain a row for each minute of the day during office hours, so will end up fairly large and huge if multiple periods and years are put together.)
You can use string operations:
SELECT DISTINCT substring_index(substring_index(TABLE_NAME, '_', 2), '_', -1)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = database_name

SQL query for percentage calculation - single column, all data, using like/wildcard

I'm looking for SQL query that will give me a simple percentage value based upon the number of occurrences of a value in a table with a single data column.
Example:
Table has single column of data, which has a header and 10 data rows:
COLUMN_HEADER
XYZ://abc123xyz456-0
XYZ://abc123xyz456-1
XYZ://abc123xyz456-2
XYZ://abc123xyz456-3
ABC://abc123xyz456-4
XYZ://abc123xyz456-5
XYZ://abc123xyz456-6
ABC://abc123xyz456-7
XYZ://abc123xyz456-8
XYZ://abc123xyz456-9
I'm looking for the query to look for all data that does not start with XYZ://*
and give that as a % of the row count.
In the above example, there are two rows that start with ABC:// and eight that start XYZ:// therefore the result should be:
80.00%
(so 8 out of 10 rows do not start with XYZ://)
As you can tell by now I'm a noob in SQL.
MS SQL 2014
Thanks in advance.
You can do this with conditional aggregation:
select avg(case when COLUMN_HEADER like 'XYZ://%' then 1.0 else 0 end) as xyz_ratio
Your logic and examples are backwards. 80% of the rows have values that do start with "XYZ://". Use like or not like as appropriate.

how do ssrs groups work?

I'm trying to understand how ssrs formats the way data is presented. I have a table in ssms and a sp that gets the data from that table. The sp code is:
select *
from [CustData]
where 1 = 1
and (reportYear = #dbParam_reportYear or reportYear = #dbParam_reportYear-1 )
and marketCode=#dbParam_marketCode
and brandName=#dbParam_brandName
and (contactSegmentDesc=#dbParam_contactSegmentDesc)
order by reportYear ASC, reportMonth ASC
This obviously returns the data row by row i.e. if the report year param is 2014, then the rows with 2014 and then rows with 2013 data.
image:
This is then used in ssrs in a report but the data is presented by columns. The column group is like [segmentDesc] [reportMonth] [reportYear] followed by all the data that is retrieved.
image:
I need to know what is formatting the data output from row by row to column by column presentation. I do suspect its the column groups but need to confirm. I am new to this.
Getting difference of the values:
This can be conducted with use of SSRS matrix. Here is a nice tutorial: https://www.youtube.com/watch?v=zERexbgCG5A
The delta can be calculated with the following approach: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/e77d6526-cadc-4d14-8ca3-997d58cb7c4a/ssrs-matrix-difference-between-columns?forum=sqlreportingservices
Notice the following:
=(Code.GetMaxValue(RunningValue(Fields!Month.Value,CountDistinct,"Services"),(Fields!Amount.Value)-Previous(FIRST(Fields!Amount.Value))))

MS Access Query to output all values and treat unavailable values as zero

I've created a query MS Access 2010 that is intended to take all fuel types (all values) for each date. I have the query relationship below: ) and have the following 6 values for fuel type: Diesel #2, MSFO, ULSD, Biodiesel, Used Oil, Heat Recovery.
I'm trying to output the fuel delivery for each fuel type for each date regardless if there's any fuel delivered that date
and
. What I'm getting as my output is below
.
I have tried to change the relationships such that all values on tbl_FuelType would output. This gave me the output on the figure above. I've tried entering a criteria to look for the specific fuel type (e.g. "ULSD") but if there's no data for that day, it will output with Null values, which I don't want. See criteria below
I've tried some program flow functions such as IIF and Switch but still getting null values. Is there an easy way to do this without having to go into the table and filling out values as zero's for all the different fuel types on the tbl_FuelDelivery? The SQL view is as follows:
SELECT tbl_FuelDelivery.DateLog, Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Gross],0)) AS Fuel_Delivery_Gross, Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Net],0)) AS Fuel_Delivery_Net, tbl_FuelType.FuelType
FROM tbl_FuelType LEFT JOIN tbl_FuelDelivery ON tbl_FuelType.ID = tbl_FuelDelivery.FuelType
GROUP BY tbl_FuelDelivery.DateLog, tbl_FuelType.FuelType
ORDER BY tbl_FuelDelivery.DateLog;
​
What you need to add to your query is a table with all dates. You can have a separate table where all dates are entered, such a calendar table or have it derived from your tbl_FuelDelivery like this:
SELECT DISTINCT tbl_FuelDelivery.DateLog
FROM tbl_FuelDelivery;
Now, you need to CROSS JOIN this table with tbl_FuelType. Access does not natively support cross joins, so you'll have to use a workaround: just add the cross join as a comma separated table to your FROM clause:
SELECT a.DateLog, tbl_FuelType.FuelType, tbl_FuelType.ID
FROM (SELECT DISTINCT tbl_FuelDelivery.DateLog FROM tbl_FuelDelivery) a,
tbl_FuelType;
The query above will give you the all fuel types for all dates. You can save it as a new query (let's call it allDatesFuels). Now, all you need to do is to join it with your query:
SELECT
allDatesFuels.DateLog,
Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Gross],0)) AS Fuel_Delivery_Gross,
Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Net],0)) AS Fuel_Delivery_Net,
allDatesFuels.FuelType
FROM allDatesFuels LEFT JOIN tbl_FuelDelivery ON allDatesFuels.ID = tbl_FuelDelivery.FuelType And allDatesFuels.DateLog = tbl_FuelDelivery.DateLog
GROUP BY allDatesFuels.DateLog, allDatesFuels.FuelType
ORDER BY allDatesFuels.DateLog;
​