Add additional expression column to cross-tab - Is this possible? - sql

I have a cross-tab that aggregates values by month and year as averages. The only component left is calculating the spread between the two agg. function columns. The user is able to pick the two nodes in which they want to see the spreads for. The user can also pick the year.
Here is the code:
PARAMETERS [Node 1] Long, [Node 2] Long, [Year] Long;
TRANSFORM Format(Avg([Monthly values].[total_lmp_on]),"Fixed") AS AVG_ON_LMP
SELECT [Monthly values].Month, [Monthly values].Year
FROM [Monthly values]
WHERE ((([Monthly values].pnode_id)=[Node 1] Or ([Monthly values].pnode_id)=[Node 2])AND [Monthly values].Year = [Year])
GROUP BY [Monthly values].Month, [Monthly values].Year
PIVOT [Monthly values].pnode_id;
The user is prompted Node 1, Node 2, and year. Lets say:
Node 1: 12345
Node 2: 6789
Year: 2017
The following will show:
Month--------------Year-----------12345--------------6789
Jan-----------------2017------------10-----------------20
Feb-----------------2017------------15-----------------15
March----------------2017------------5-----------------0
April-----------------2017------------20-----------------10
The problem
How can I add a column that will give me the spread between the two chosen nodes? Which would look like:
Month--------------Year-----------12345--------------6789-------------Spread
Jan-----------------2017------------10-----------------20----------------(-10)
Feb-----------------2017------------15-----------------15-----------------(0)
March----------------2017------------5-----------------0------------------(5)
April-----------------2017------------20-----------------10---------------(10)
I am fairly certain this isn't possible, but would like to exhaust all resources. Or if there are any other options out there.

Consider conditional aggregation using AVG(IIF(...)) to find the difference of corresponding node averages. Do note: Spread column will appear to the right of pivoted columns.
PARAMETERS [Node 1] Long, [Node 2] Long, [Year] Long;
TRANSFORM Format(AVG(m.[total_lmp_on]), "Fixed") AS AVG_ON_LMP
SELECT m.Month, m.Year,
AVG(IIF(m.pnode_id = [Node1], m.[total_lmp_on], NULL)) -
AVG(IIF(m.pnode_id = [Node2], m.[total_lmp_on], NULL)) AS Spread
FROM [Monthly values] m
WHERE (m.pnode_id) IN ([Node 1], [Node 2]) AND (m.Year = [Year])
GROUP BY m.Month, m.Year
PIVOT m.pnode_id;

Related

SQL - Display columns from two tables with where clause, preform count and GROUP BY COLUMNS in one table

I have two tables. One table is the main registered Boat table that holds most of the information. it has many columns one of them is [MFR CODE].
The other table is a reference table that contains all the records associated with only Business Boats and it has only 3 columns : [MFR CODE], [MFR NAME] & [MODEL]
I'm trying to find how many times (count) Business Boats appear in the Registered boat tables.
SELECT
Count(*) As 'TotalNumberBoats'
, [BoatsReg].[dbo].[MASTER].[MFR MDL CODE]
,[BoatsReg].[dbo].[BusinessBoats].[MFR]
,[BoatsReg].[dbo].[BusinessBoats].[MODEL]
FROM [BoatsReg].[dbo].[MASTER],[BoatsReg].[dbo].[BusinessBoats]
Where [BoatsReg].[dbo].[MASTER].[MFR MDL CODE] = [BoatsReg].[dbo].[BusinessBoats].[CODE]
group by [BoatsReg].[dbo].[BusinessBoats].[CODE]
order by TotalNumberBoats asc
How do i get rid of all the square brackets, it's annoying.
why do i get an error ?
Well when you aggregate a result, you have to specify all other fixed columns in the GROUP BY clause
(Answer edited to add total row with a UNION ALL and add a sort field to put the total row as last one)
In your case:
SELECT 1 as sorted,
,Count(*) As TotalNumberBoats
,MASTER.[MFR MDL CODE]
,BusinessBoats.MFR
,BusinessBoats.MODEL
FROM BoatsReg, BusinessBoats
Where MASTER.[MFR MDL CODE] = BusinessBoats.CODE
Group by
,MASTER.[MFR MDL CODE]
,BusinessBoats.MFR
,BusinessBoats.MODEL
UNION ALL
SELECT 2 as sorted,
,Count(*) As TotalNumberBoats
,'','',''
FROM BoatsReg
Order by sorted, TotalNumberBoats

How to add 2nd price column in SQL when info is normally stored on 2 separate rows

I currently have a very simple SQL script, which provides the sell price for a special customer of ours, who gets Priceline "J". I'd like to add a column of Retail pricing as well for them to reference, which is normally Priceline "R". My query currently looks like this:
SELECT RS_PCL.SKU,
RS_PCL.SKU_DESC,
RS_PCL.PACKAGE,
RS_PCL.PRICE AS [Sell Price],
RS_PCL.STD AS [Start Date],
RS_PCL.END AS [End Date]
FROM RS_PCL
WHERE RS_PCL.PRICELINE = "J"
Would anyone be able to help me figure out how I could add the "R" price line as another column instead of separate rows?
I can add WHERE RS_PCL.PRICELINE IN ("J","R") but it would create a separate row for each Retail price, instead of in the column next to it. I've seen examples of a separate SELECT CASE WHEN, but not sure exactly how the syntax works.
The prices are always going to have the same start date, so it would just need to join where the SKU matches and the Start Date matches.
NOTE : IM sorry I accidentally edited your answer, not my question...
Revised: Running into errors with this code still, saying "Your query does not include the specified expression 'GL Type' as part of an aggregate function" or would say each field that isn't included in the group by clause
SELECT RS_PCL.[GL Type],
RS_PCL.SKU,
RS_PCL.[SKU Desc],
RS_PCL.Supplier,
RS_PCL.[Case UPC],
RS_PCL.[Pack UPC],
RS_PCL.[Unit UPC],
RS_PCL.PDCN,
RS_PCL.Package,
RS_PCL.[Price Start Date],
RS_PCL.[Price End Date],
Iif( RS_PCL.PRICELINE = "J" , RS_PCL.Price , Null) AS [Sell Price],
Iif( RS_PCL.PRICELINE = "R" , RS_PCL.Price , Null) AS [Retail Price],
RS_PCL.Cost,
RS_PCL.Tax,
RS_PCL.Freight
FROM RS_PCL
WHERE (RS_PCL.PRICELINE IN ("J","R"))
Tested the Self Join query listed below, I keep getting a "Syntax Error in FROM Clause" with this query.
SELECT J.*, R.R_PRICE FROM RS_PCL AS J
INNER JOIN SELECT (RS_PCL.SKU, RS_PCL.[Price Start Date], RS_PCL.Price AS R_PRICE FROM RS_PCL WHERE RS_PCL.PRICELINE = "R") AS R
ON J.SKU = R.SKU AND J.[Price Start Date] = R.[Price Start Date]
WHERE RS_PCL.Priceline = "J"
SELECT CASE does not work in Access query. Use IIf() or Switch() or Choose().
Perhaps a CROSSTAB query or emulate CROSSTAB with expressions to create fields. Presuming, as indicated in question title, there is one "J" and one "R" record for each data combination:
SELECT SKU, SKU_DESC, PACKAGE, STD, END,
Max(IIf(PRICELINE = "J", PRICE, Null)) AS J,
Max(IIf(PRICELINE = "R", PRICE, Null)) AS R
FROM RS_PCL
GROUP BY SKU, SKU_DESC, PACKAGE, STD, END
Or a self-join, assuming only fields needed as unique identifier are SKU and STD:
SELECT J.*, R.R_PRICE FROM RS_PCL AS J
INNER JOIN (SELECT SKU, STD, PRICE AS R_PRICE FROM RS_PCL WHERE PRICELINE = "R") AS R
ON J.SKU = R.SKU AND J.STD = R.STD
WHERE PRICELINE = "J";
This would be useful on a report but useless for a data entry form.
Yet another approach would use DLookup() domain aggregate function. Domain aggregate function can cause slow performance in query or form but the dataset would be editable.

SUM and multiplying on calculated fields

I have a piece of script which is pulling through the desired figures fine. Now I need to multiply the figure given by another calculated field (I shall call field x, which is a case statement with 9 'When Statements') then multiply that by 0.74.
I can not get this to work at all... any ideas... script below
Case
when Left([dbo].[Table1].FIELD 1,3) = 'NEW' and [Field 2] = 'Live'
Then
(SELECT distinct[dbo].[Table2].[Field a]
FROM [MY_DATABASE].[dbo].[Table2]
right Join [dbo].[Table 3]
on ([dbo].[Table2].[Field b]=[dbo].[Table 3].[Field 1])
Where [dbo].[Table2].[Field c] =
(Select
[dbo].[Table 3].[Field1]
From [dbo].[Table 3]
Where [dbo].[Table 3].[Field4] = #parameter
and [Field5] = '7')
and [dbo].[Table2].[Field D]= #Parameter
and [dbo].[Table2].[Field E]= '07')
ELSE 0
END
As [Named Field]
One option here would be common table expressions.
I'd suggest wrapping your select in a cte, the selecting from it and performing any further calculations at the bottom level.
;with cte as (
your original select query
)
select *
, [named field] * [field x] as [calculated answer]
from cte
This saves you having to make the calculations over and over again. There are performance concerns around cte's but they can help in these situations. I'd test on your data and see how much of a hit you take.

T-SQL Query will not return 0 value for a Sum

I have a query where I'm calculating Days of Therapy for medications. I want to have 0 values to show for months that have no data. Currently the query returns no record if the Sum is 0. Can't seem to figure this out. See the Query Below:
If I were to comment out identifiers related to the DOT_ALL table along with the Where Clause I get 60 rows, 1 for each month for the past 5 years. However, otherwise i get only 57 for the drug in the Where Clause since there are not DOTs for Aug 2016, April 2016 and Jan 2015.
Thanks in advance.
----------------------------------------------------------------------------
SELECT
AMS.[Medication Name]
, SUM(AMS.DOT) AS DOT
, PD.[Patient Days]
, PD.[Month_Name]
, PD.[Fiscal_Month]
, PD.[Accounting_Year]
, PD.[Year]
FROM
DW_PROD.dbo.Patient_Days_By_Month PD
Left JOIN [DW_PROD].[dbo].[DOTS_All] AMS ON (PD.Month_Name = AMS.Month AND PD.Year = AMS.Year)
WHERE
[Medication Name] = 'CEFUROXIME'
GROUP BY
AMS.[Medication Name]
, PD.[Patient Days]
, PD.[Month_Name]
, PD.[Fiscal_Month]
, PD.[Accounting_Year]
, PD.[Year]
ORDER BY
ACCOUNTING_YEAR
,FISCAL_MONTH
This may be the cheapest solution, under the assumption that Patient_Days_By_Month is already some kind of calendar.
SELECT
'CEFUROXIME' AS [Medication Name],
SUM(AMS.DOT) AS DOT,
PD.[Patient Days],
PD.[Month_Name],
PD.[Fiscal_Month],
PD.[Accounting_Year],
PD.[Year]
FROM DW_PROD.dbo.Patient_Days_By_Month PD
LEFT JOIN [DW_PROD].[dbo].[DOTS_All] AMS
ON PD.Month_Name = AMS.Month
AND PD.Year = AMS.Year
AND [Medication Name] = 'CEFUROXIME'
GROUP BY
PD.[Patient Days],
PD.[Month_Name],
PD.[Fiscal_Month],
PD.[Accounting_Year],
PD.[Year]
ORDER BY
PD.ACCOUNTING_YEAR,
PD.FISCAL_MONTH
JOIN conditions do not need to refer to columns in other tables, they can as well contain constants.
The medication name was originally restricted in the WHERE clause - that eliminated all non-cefuroxime records from the resultset.

SQL Server 2012 Max Date in Subquery in a joined table

I manage a state wide application and use Tableau to create visualizations of data.
I have been tasked with creating a visualization that show how much time is passing between contact entries and today (Case Note Dates). I know how to isolate the max case note date in the case note table:
Select
[Case_Master_ID],
[Case_Note_Date],
[Case_Note_Category_Desc],
[Case_Note_Summary_Narr]
From
buCase_Note
Where
Case_Note_Date = (Select MAX(Case_Note_Date)
From buCase_Note)
This query will show me that max case notes in the table from today. The issue is I need to show the max case note for all participants, not just the ones from today. The original query I have been using to view case notes is:
Select
vc.[_Case Master ID],
vc.[_Caseload Assignment Current],
vc.[_Participant Name],
vc.[Case Status],
vc.[Reporting Structure Level 4],
vc.[Reporting Structure Level 5],
vc.[Application Date],
vc.[Eligibility Date],
vc.[Eligibility Determination Extension Date],
vc.[Eligibility Extended To Date],
vc.[Days in Application],
cn.[Case_Note_Date],
cn.[Case_Note_Category_Desc],
cn.[Case_Note_Summary_Narr]
From
biVR_Cases vc
Left outer Join
buCase_Note cn ON cn.Case_Master_ID = vc.[_Case Master ID]
I need to keep biVR_Cases on the left to show all the open clients. Then I need to join in the case note table and for every participant, I want to show their max case note date. When I add this to the end of the above query:
Where cn.[Case_Note_Date] = (
Select
MAX(cn.Case_Note_Date)
From buCase_Note)
I get the following error is SSMS 2012:
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
I am looking to retain the bi table on the left while successfully joining in the case note table and bringing in only the most recent case note per participant.
Adding details:
Of course,
Here is a sample of data I get when running the following query:
Select
vc.[_Case Master ID],
vc.[_Caseload Assignment Current],
vc.[_Participant Name],
cn.[Case_Note_Date],
From biVR_Cases vc
LEFT outer JOIN buCase_Note cn ON vc.[_Case Master ID] = cn.Case_Master_ID
_Caseload Assignment Current Test Participant Name Casenote Date
Test Counselor Participant A
September 29, 2010
September 23, 2010
August 30, 2010
June 30, 2010
June 1, 2010
The bi table contains participant information like name, application, case master ID, etc. The casenote table contains the case master ID as well hence the join. It also contains the dates each entry is created. So for the dataset above, I am trying to only bring in the most recent casenote for each participant. I only included 1 in the sample above, but we have over 15,000. Each participant will have many case notes. I am trying to grab the top casenote so I can calculate the date difference between the most recent case note and today for each participant. When I add :
Where cn.[Case_Note_Date] = (Select
top 1 [Case_Note_Date]
From buCase_Note
Order by 1 DESC))
OR
Where Case_Note_Date=(
Select
MAX(Case_Note_Date)
From buCase_Note)
It is only showing the top or max casenote for participants that had a casenote created today. Instead of showing the max casenote in the casenote table, I need the max casenote per participant. I hope that makes more sense.
You might try something like what I have included below. Without actual data, I do not know if it is efficient enough for you, but it should work. If you get a better answer, however, I would love to know it.
Select vc.[_Case Master ID],
vc.[_Caseload Assignment Current],
vc.[_Participant Name],
vc.[Case Status],
vc.[Reporting Structure Level 4],
vc.[Reporting Structure Level 5],
vc.[Application Date],
vc.[Eligibility Date],
vc.[Eligibility Determination Extension Date],
vc.[Eligibility Extended To Date],
vc.[Days in Application],
cn.[Case_Note_Date],
cn.[Case_Note_Category_Desc],
cn.[Case_Note_Summary_Narr]
From biVR_Cases vc
LEFT outer JOIN
(SELECT Case_Master_ID, Case_Note_Date, Case_Note_Category_Desc, Case_Note_Summar_Narr,
ROW_NUMBER() OVER (PARTITION BY Case_Master_ID ORDER BY Case_Note_Date DESC) as RowNum FROM buCase_Note) cn
ON cn.Case_Master_ID = vc.[_Case Master ID] AND cn.RowNum=1
Remove the cn. from the MAX(cn.Case_Note_Date) row. You don't want to reference column from the main query. You just want to select a Case_Note_Date from buCase_Note.
So the whole query will be
Select
vc.[_Case Master ID],
vc.[_Caseload Assignment Current],
vc.[_Participant Name],
vc.[Case Status],
vc.[Reporting Structure Level 4],
vc.[Reporting Structure Level 5],
vc.[Application Date],
vc.[Eligibility Date],
vc.[Eligibility Determination Extension Date],
vc.[Eligibility Extended To Date],
vc.[Days in Application],
cn.[Case_Note_Date],
cn.[Case_Note_Category_Desc],
cn.[Case_Note_Summary_Narr]
From biVR_Cases vc
LEFT outer JOIN buCase_Note cn ON cn.Case_Master_ID = vc.[_Case Master ID]
Where cn.[Case_Note_Date] = (Select
MAX(Case_Note_Date)
From buCase_Note)