Add a column to a multiple SELECT SQL query string - sql

The below code works, but I want to add the column "segvalue1" to my query result:
SELECT (SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYTD
FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod between 1 AND 10
AND Company = 'NVV' AND FiscalYear = 2017),
(SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYM
FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod = 10
AND Company = 'NVV' AND FiscalYear = 2017)
So I modified the code to look like the below but it gives me 2 "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS" errors :
SELECT (SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYTD,
segvalue1 FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod
between 1 AND 10 AND Company = 'NVV' AND FiscalYear = 2017
GROUP BY segvalue1),
(SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYM,
segvalue1 FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod = 10
AND Company = 'NVV' AND FiscalYear = 2017
GROUP BY segvalue1)
Does anyone know how to modify the code to get my desired result? Again, I am just trying to pull in the segvalue1 column. Once I figure this out, I will also pull in a couple more columns. Thanks for your help!

Consider conditional aggregation:
SELECT segvalue1,
SUM(CASE WHEN FiscalPeriod BETWEEN 1 AND 10
THEN DebitAmount-CreditAmount
ELSE NULL
END) as BalanceAmtCYTD,
SUM(CASE WHEN FiscalPeriod = 10
THEN DebitAmount-CreditAmount
ELSE NULL
END) as BalanceAmtCYM
FROM GLJrnDtl WITH (NOLOCK)
WHERE Company = 'NVV' AND FiscalYear = 2017 -- SHARED CONDITION
GROUP BY segvalue1

Related

How to get year numbers in columns

I need to display the number of transactions in individual years for individual employees (ID, 2011, 2012, 2013, 2014) and I should see the number of transactions in every year under years number, but now I receive this form:
How can I change it?
I think I should use WHERE, but I dont know how to do it
My current query is:
SELECT oh.SalesPersonID AS perID,
YEAR(oh.OrderDate) AS [Year], COUNT(*)
FROM Sales.SalesOrderHeader oh
JOIN Person.Person per ON oh.SalesPersonID = per.BusinessEntityID
GROUP BY SalesPersonID, YEAR(OrderDate)
ORDER BY perID, [Year];
Just use conditional aggregation:
SELECT oh.SalesPersonID AS perID,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2011 THEN 1 ELSE 0 END) as cnt_2011,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2012 THEN 1 ELSE 0 END) as cnt_2012,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2013 THEN 1 ELSE 0 END) as cnt_2013,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2014 THEN 1 ELSE 0 END) as cnt_2014
FROM Sales.SalesOrderHeader oh JOIN
Person.Person per
ON oh.SalesPersonID = per.BusinessEntityID
GROUP BY SalesPersonID
ORDER BY perID;

Select "case when"... yields grouped results... how to obtain aggregate data?

Newer SQL user working with SQL Server 2014 SP2.
I'm trying to determine how to improve my results on a particular query.
The problem is that when I select data with a Case When, it requires me to use group by to aggregate the data.
I am trying to eliminate this group by, and have not been able to determine a viable method for this query.
Query yields these results:
StoreID Devices playing devices FullScreenPlays PIPPlays
--------------------------------------------------------
1296 1 0 0 0
1296 7 7 7 0
1296 7 7 0 7
I am trying to achieve something more like this:
StoreID Devices playing devices FullScreenPlays PIPPlays
--------------------------------------------------------------
1296 8 7 7 7
I've tried several variants of calling the group by, and I've tried several variants of the case when, but I can't seem to figure out what I'm doing wrong...
Any insight would be appreciated!
SQL code is here:
DECLARE #Location varchar(50) = '1296'
SELECT
Location.ExternalCode As [StoreID],
COUNT(DISTINCT imdd.DeviceID) AS Devices,
COUNT(DISTINCT esr.DeviceID) AS [playing devices],
(CASE
WHEN (esr.EventID = 925)
THEN (COUNT(DISTINCT esr.DeviceID))
ELSE 0
END) AS [FullScreenPlays],
(CASE
WHEN (esr.EventID = 926)
THEN (COUNT(DISTINCT esr.DeviceID))
ELSE 0
END) AS [PIPPlays]
FROM
[iSenseMD].dbo.Location WITH (NOLOCK)
INNER JOIN
iSenseMD.dbo.LocationAttribute la WITH (NOLOCK) ON Location.LocationID = la.LocationID
AND la.AttributeID = 7
AND la.Value = 1
LEFT JOIN
[iSenseMD].[dbo].Device imdd WITH (NOLOCK) ON location.LocationID = imdd.LocationID
AND imdd.DeviceName NOT IN ('iX Gateway', 'A312778', 'A294874', '334873')
LEFT JOIN
[iSenseAnalytics].[dbo].[EventStringRollup] esr WITH (NOLOCK) ON imdd.LocationID = esr.LocationID
AND imdd.DeviceID = esr.DeviceID
AND esr.IntervalID = 1
AND esr.EventID IN (925, 926) --all plays
AND esr.RollupTimestamp >= dateadd(day, datediff(day, 1, GETDATE()), 0)
AND esr.RollupTimestamp < dateadd(day, datediff(day, 0, GETDATE()), 0)
WHERE
Location.IsActive = 1
AND Location.LocationName NOT LIKE '%duplicate%'
AND Location.ExternalCode = #Location --this to add the declaration above as site constraint
GROUP BY
Location.ExternalCode, esr.EventID
ORDER BY
iSenseMD.dbo.Location.ExternalCode
Any insight would be appreciated!
Thanks!
I would put the query in a CTE and then aggregate it from there
WITH CTE_Example
AS
( use iSenseMD
go
DECLARE #Location varchar(50) = '1296'
SELECT Location.ExternalCode As [StoreID]
,count(distinct imdd.DeviceID) as Devices
,count(distinct esr.DeviceID) as [playing devices]
,(case when (esr.EventID = 925) Then (count (distinct esr.DeviceID)) Else 0 End) As [FullScreenPlays]
,(case when (esr.EventID = 926) Then (count (distinct esr.DeviceID)) Else 0 End) As [PIPPlays]
FROM [iSenseMD].dbo.Location WITH (NOLOCK)
INNER JOIN iSenseMD.dbo.LocationAttribute la WITH (NOLOCK)
ON Location.LocationID = la.LocationID
AND la.AttributeID = 7
AND la.Value = 1
left JOIN [iSenseMD].[dbo].Device imdd WITH (NOLOCK) ON location.LocationID = imdd.LocationID
AND imdd.DeviceName NOT IN ('iX Gateway','A312778','A294874','334873')
left JOIN [iSenseAnalytics].[dbo].[EventStringRollup] esr WITH (NOLOCK) ON imdd.LocationID = esr.LocationID and imdd.DeviceID = esr.DeviceID
AND esr.IntervalID = 1
AND esr.EventID IN (925, 926) --all plays
AND esr.RollupTimestamp >= dateadd(day,datediff(day,1,GETDATE()),0)
AND esr.RollupTimestamp < dateadd(day,datediff(day,0,GETDATE()),0)
WHERE Location.IsActive = 1
AND Location.LocationName NOT LIKE '%duplicate%'
AND Location.ExternalCode = #Location --this to add the declaration above as site constraint
GROUP BY Location.ExternalCode
,esr.EventID)
--A GROUP BY might not be allowed either, I can't remember. But I think it'll be fine, let me know if there are any issues
/* ORDER BY
iSenseMD.dbo.Location.ExternalCode */
--I don't think an ORDER BY is allowed in a CTE so I have it commented out for now. Is it an absolute within the query?
SELECT StoreID, SUM(Devices), SUM([playing devices]), SUM(FullScreenPlays),
SUM(PIPPlays)
FROM CTE_Example
GROUP BY StoreID
Hope this helps and please let me know if there are any errors!
You need to place your case statement inside your count aggregate. This way you can remove the EventID in the group by
Example:
COUNT(DISTINCT
CASE WHEN (esr.EventID = 925) THEN esr.DeviceID
ELSE NULL
END) AS [FullScreenPlays]
Original:
(CASE
WHEN (esr.EventID = 925)
THEN (COUNT(DISTINCT esr.DeviceID))
ELSE 0
END) AS [FullScreenPlays]

SQL Query optimization Statistics

I was wondering if someone can give me a query to get the result.
Initial Table:
ID Year Quantity
Result Table:
ID 2009_Quantity 2010_Quantity 2011_Quantity ...
What I did now was:
Select ID
, (select sum(Id.Quantity) from Initial_Database id where id.Year = 2009)
, (select sum(Id.Quantity) from Initial_Database id where id.Year = 2010)
from Initial_Database i
Group BY ID
But this is taking hours for millions of records, and this is nog an option.
I also tried:
Select ID
, CASE WHEN i.Year = 2009 THEN sum(Id.Quantity) ELSE 0 END
, CASE WHEN i.Year = 2010 THEN sum(Id.Quantity) ELSE 0 END
from Initial_Database i
Group BY ID
Faster, But this gives me 2 lines which I don't want.
Try like this:
Select ID
, SUM(CASE WHEN i.Year = 2009 THEN Id.Quantity ELSE 0 END)
, SUM(CASE WHEN i.Year = 2010 THEN Id.Quantity ELSE 0 END)
from Initial_Database i
Group BY ID

Annual Count by Criteria

I am working on a project with our HR department.
I have a table called [EEMaster] that keeps a record of the Active/Termed employees.
It is updated from a flat File using a Slowly Changing Dimension.
At the end of the year I need a count of the number of Active employees and the number of termed employees and then the year.
Here is an example of the data I need returned annually.
| 2010 | 2011 | 2012 | 2013 |
HistoricalHC | 447 | 419 | 420 | 418 |
NumbTermEmp | 57 | 67 | 51 | 42 |
I currently have the data connected to an excel spreadsheet providing a rolling count by Division. I use the following columns from the [EEMaster] for it.
ChangeStatus (1/0 from the SCD)
EmpStatusName ("Active" for current employees and "Withdrawn" for Termed Employees)
HireYear (set to All in the pivot table)
Term Year (set to 2013 in the pivot table)
PONumb (The employee numbers, I use for the count)
I have created a table to input the data into, I will manually load the previous years (counts)into the table since the current development is a rolling number. What I want to do is to develop an SSIS package that will capture the count on Jan 1 of 2014 and insert the # of "Active Employees", "Termed Employees" and the Year that just finished into a table.
UPDATE:
I have created two queries. One that provides the number of Active Employees
SELECT COUNT([PersNo]) AS HistoricalHC
FROM [dbo].[EEMaster]
WHERE [ChangeStatus] = 'Current' AND [EmpStatusName] = 'Active'
it returns
|HistoricHC|
|418 |
And another that provides the number of terms by Term Year
SELECT COUNT([PersNo]) AS NumbOfTermEE
FROM [dbo].[EEMaster]
WHERE [ChangeStatus] = 'Current' AND [EmpStatusName] = 'Withdrawn'
AND [TermYear] = '2013'
it returns
|NumbOfTermEE|
|42 |
I need the [TermYear] to be dynamic. Since this will run on Jan 1st of every year. It would need to pull the number of terms for the previous year (continually).
Then I need both of these numbers to be added into the new row with the year the data was calculated.
|Year|HistoricalHC|NumbOfTermEmp|
|2010|447 |57 |
|2011|419 |67 |
|2012|420 |51 |
|2013|418 |42 |
You are looking for a syntax of a case expression that does an aggregate to add a few for different things.
Sum(Case when (expression) then 1 end)
You also want to group by year it seems in the columns so you can easily pivot on that. You mention dynamic but I don't really know if you need to get much dynamic for just the year logic. I am not really getting if you want a SQL statement to go in a data flow to generate an output of an Excel sheet or not. Basically if you want just a grid with one row being one set of conditions and another being another. I would do a 'union' of two or more selects as long as it is not too large it should not be that hard. Here is a simple self extracting example with dummy data to see what I mean more.
It will run as is in SQL Management Studio 2005 and up.
declare #Person Table ( personID int identity, person varchar(8));
insert into #Person values ('Brett'),('Sean'),('Chad'),('Michael'),('Ray'),('Erik'),('Queyn');
declare #Orders table ( OrderID int identity, PersonID int, OrderCnt int, dt Date);
insert into #Orders values (1, 10, '1-7-11'),(1, 12, '2-12-12'),(2, 20, '7-1-13'),(2, 12, '1-5-10'),(3, 20, '6-4-11')
,(3, 12, '2-3-10'),(3, 6, '6-10-10'),(4, 20, '7-10-11'),(5, 20, '1-8-10'),(5, 9, '2-10-11'),
(6, 20, '3-1-11'),(6, 34, '4-6-12'),(7, 20, '5-1-11'),(7, 12, '6-8-12'),(7, 56, '7-25-13')
-- As is just joining sets
select *
from #Person p
join #Orders o on p.personID = o.PersonID
order by dt
-- Years on the rows
select
year(o.dt) as Year
, sum(o.OrderCnt) as Orders
, count(p.personID) as People
, count(distinct p.personID) as DistinctPeople
from #Person p
join #Orders o on p.personID = o.PersonID
group by year(o.dt)
-- Custom grouping on rows and doing the years with pivots for the columns
Select
'BulkOrders' as Description
, sum(case when year(o.dt) = '2010' then OrderCnt end) as [2010Orders]
, sum(case when year(o.dt) = '2011' then OrderCnt end) as [2011Orders]
, sum(case when year(o.dt) = '2012' then OrderCnt end) as [2012Orders]
, sum(case when year(o.dt) = '2013' then OrderCnt end) as [2013Orders]
, sum(OrderCnt) as Totals
from #Person p
join #Orders o on p.personID = o.PersonID
union
select
'OrdersByPerson'
, Count(case when year(o.dt) = '2010' then p.personID end)
, Count(case when year(o.dt) = '2011' then p.personID end)
, Count(case when year(o.dt) = '2012' then p.personID end)
, Count(case when year(o.dt) = '2013' then p.personID end)
, Count(p.personID)
from #Person p
join #Orders o on p.personID = o.PersonID
union
select
'OrdersByPersonDistinct'
, Count(distinct case when year(o.dt) = '2010' then p.personID end)
, Count(distinct case when year(o.dt) = '2011' then p.personID end)
, Count(distinct case when year(o.dt) = '2012' then p.personID end)
, Count(distinct case when year(o.dt) = '2013' then p.personID end)
, Count(distinct p.personID)
from #Person p
join #Orders o on p.personID = o.PersonID
Here is the solution I cam up with.
I will create an SSIS package that will run the following Stored Procedure.
INSERT INTO [dbo].[TORateFY] (Year,HistoricalHC,NumbTermedEmp)
SELECT DISTINCT YEAR(GETDATE()) AS [Year],
SUM(CASE WHEN EmpStatusName = 'Active' THEN 1 ELSE 0 END) AS HistoricalHC,
SUM(CASE WHEN EmpStatusName = 'Withdrawn' AND TermYear = YEAR(GETDATE()) THEN 1 ELSE 0 END) AS NumbOfTermEE
FROM dbo.EEMaster
This will be scheduled to run Annually on the 31st of Dec.
Update to my previous Answer:
I worked with a guy on another forum and he provided an excellent script that will give the correct count for both the active and termed employees on a monthly basis instead of waiting until the end of the year to get an overall count. This puts the reporting more inline with what was originally done manually.
MERGE dbo.TORateFY AS tgt
USING (
SELECT DATENAME(YEAR, GETDATE()) AS [Year],
SUM(CASE WHEN EmpStatusName = 'Active' THEN 1 ELSE 0 END) AS HistoricalHC,
SUM(CASE WHEN EmpStatusName = 'Withdrawn' AND TermYear = DATENAME(YEAR,
GETDATE()) THEN 1 ELSE 0 END) AS NumbOfTermEE
FROM dbo.EEMaster
WHERE ChangeStatus = 'Current'
AND EmpStatusName IN ('Active', 'Withdrawn')
OR TermYear <= DATENAME(YEAR, GETDATE())
) AS src ON src.[Year] = tgt.[Year]
WHEN MATCHED
THEN UPDATE
SET tgt.HistoricalHC = src.HistoricalHC,
tgt.NumbTermedEmp = src.NumbOfTermEE
WHEN NOT MATCHED BY TARGET
THEN INSERT (
[Year],
HistoricalHC,
NumbTermedEmp
)
VALUES (
src.[Year],
src.HistoricalHC,
src.NumbOfTermEE
);
I wanted to share the in case anyone else ran into a similar situation.
Thank you everyone for your input and guidance.

SQL Query to compare 2 weeks

I've got to design a query in visual studio where I have 2 data sets.
basically it goes like this.
I want to compare this weeks call total to last week per country calling.
the only thing is last weeks calls may have come from 20 diff countries while this weeks might only have come from 15.
How can I make the query such that the 20 countries will show up for both while having "0" value in for countries that do not appear this week.
below is my query:
Select country,
Sum(Case When actstatus in (5,105) Then 1 Else 0 End) As TotalCalls,
Sum(Case When actstatus = 105 Then 1 Else 0 End) As FailedCalls
From termactivity(nolock)
INNER JOIN termconfig(NOLOCK) ON cfgterminalID = actterminalID
INNER JOIN Country (nolock) on country = cycode
Where actstatus in (5,105)
and (actTerminalDateTime BETWEEN #StartDate-7 AND #EndDate-7)
Group By country
order By country asc
When Act status = 105 it means the call was not completed and when it = 5 it means the call was successful. I am doing this to get a successful call % rate per week.
Thanks in Advance!
Apply the same logic as you did to total calls and failed calls as you did to the this week and last week.
SELECT country,
COUNT(CASE WHEN actTerminalDateTime < #StartDate THEN 1 END) [LastWeekTotalCalls],
COUNT(CASE WHEN ActStatus = 105 AND actTerminalDateTime < #StartDate THEN 1 END) [LastWeekFailedCalls],
COUNT(CASE WHEN actTerminalDateTime >= #StartDate THEN 1 END) [ThisWeekTotalCalls],
COUNT(CASE WHEN ActStatus = 105 AND actTerminalDateTime >= #StartDate THEN 1 END) [ThisWeekFailedCalls]
FROM termactivity (NOLOCK)
INNER JOIN termconfig (NOLOCK)
ON cfgterminalID = actterminalID
INNER JOIN Country (NOLOCK)
ON country = cycode
WHERE actstatus in (5,105)
AND actTerminalDateTime BETWEEN DATEADD(DAY, -7, #StartDate) AND #EndDate
GROUP BY country
ORDER BY country ASC
I've also tidied up your query slightly, for example there is no point in specifying
WHEN ActStatus IN (5, 105) ...
When your WHERE clause already limits all results to 5, 105, therefore this is a redundant predicate in your case expression
From what I understand, you want to perform separate queries for two weeks, and you want both queries to produce rows for all countries, regardless of whether all countries had any calls. To achieve this, you need to use LEFT OUTER JOINS. The below code should guarantee that every country found in the Country table has a row, even if both sums are 0.
SELECT country,
SUM(CASE WHEN actstatus IN (5,105) THEN 1 ELSE 0 END) AS TotalCalls,
SUM(CASE WHEN actstatus = 105 THEN 1 ELSE 0 END) AS FailedCalls
FROM Country (NOLOCK)
LEFT OUTER JOIN termconfig (NOLOCK) ON country = cycode
LEFT OUTER JOIN termactivity (NOLOCK) ON cfgterminalID = actterminalID
WHERE (actTerminalDateTime BETWEEN #StartDate-7 AND #EndDate-7)
GROUP BY country
ORDER BY country ASC
If this was not what you wanted, perhaps you need to clarify your question. Many others have assumed that you want to combine the results into a single query.