The same table SQL Joins - sql

I have two select statements, my purpose is to display the sum of billing and the sum of penalty. Can it be done using joins?
SELECT SUM([Amount]) AS 'BILLING',(SELECT SUM([Amount])
FROM Transactions
WHERE CAST([TransactionDate] AS DATE)>(SELECT TOP 1 CAST([TransactionDate] AS DATE)
FROM Transactions WHERE CustNo = 6313 AND [Particulars]='Payment' ORDER BY [Id] DESC)
AND [CustNo]=6313
AND [Particulars]='Penalty') AS 'PENALTY'
FROM Transactions
WHERE CAST([TransactionDate] AS DATE)>(SELECT TOP 1 CAST([TransactionDate] AS DATE)
FROM Transactions WHERE CustNo = 6313
AND [Particulars]='Payment' ORDER BY [Id] DESC)
AND [CustNo]=6313
AND [Particulars]='Billing'

You can use conditional aggregation:
SELECT SUM(CASE WHEN [Particulars]='Billing' THEN [Amount] ELSE 0 END) AS 'BILLING',
SUM(CASE WHEN [Particulars]='Penalty' THEN [Amount] ELSE 0 END) AS 'PENALTY',
FROM Transactions
WHERE CAST([TransactionDate] AS DATE)>(SELECT TOP 1 CAST([TransactionDate] AS DATE)
FROM Transactions WHERE CustNo = 6313
AND [Particulars]='Payment' ORDER BY [Id] DESC)
AND [CustNo]=6313
AND [Particulars]='Billing'

Related

CTE function with insert statement

I have 2 queries and I need to combine them into one query with an insert statement.
This is my first query that already has an insert statement:
with q as (
select s.department
,s.months
,s.years
,count(case when s.sum_lost_time >='10:00:00' then NAME end) as RTOTALLOSTTIME
,count(case when s.sum_ot >='20' then NAME end) as ROT
from (select MONTH(STATUSIN) as [months]
,YEAR(STATUSIN) as [years]
,NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,SUM(CAST(OT AS FLOAT)) as sum_ot
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
group by s.department
,s.months
,s.years
)
INSERT INTO REPORTDATA(DEPARTMENT,MONTHS,YEARS,RTOTALLOSTTIME,ROT)
SELECT DEPARTMENT,MONTHS,YEARS,RTOTALLOSTTIME,ROT
FROM q
This is the result from first query in table REPORTDATA:
And this is my second query.
WITH cte AS
(
SELECT DISTINCT [NAME], DEPARTMENT, MONTH(STATUSIN) [MONTH], YEAR(STATUSIN) [YEAR],
SUM(CASE WHEN LATECOME = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) Total
,SUM(CASE WHEN EARLYLEAVE = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) TotalEarlyLeave
FROM SUMMARYDATA
)
SELECT SUM(CASE WHEN TOTAL > 2 THEN 1 ELSE 0 END) LATECOME,
SUM(CASE WHEN TotalEarlyLeave > 1 THEN 1 ELSE 0 END) EARLYLEAVE
FROM cte
GROUP BY DEPARTMENT, [MONTH], [YEAR]
And this is the result from second query:
I want to place it into my first query but I don't know how to combine it into one in insert statement. Can anyone solve my problems?
This is the sample to my first query: Count summary records per month with conditional SQL
and this is the sample to second query: Count records per month with condition in SQL Server
It's easy if you concatenate your queries as multiple CTEs, and finally JOIN them.
Like this :
;
with cte1 as (
select s.department
,s.months
,s.years
,count(case when s.sum_lost_time >='10:00:00' then NAME end) as RTOTALLOSTTIME
,count(case when s.sum_ot >='20' then NAME end) as ROT
from (select MONTH(STATUSIN) as [months]
,YEAR(STATUSIN) as [years]
,NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,SUM(CAST(OT AS FLOAT)) as sum_ot
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
group by s.department
,s.months
,s.years
),
cte2 as (
SELECT DISTINCT [NAME], DEPARTMENT, MONTH(STATUSIN) [MONTH], YEAR(STATUSIN) [YEAR],
SUM(CASE WHEN LATECOME = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) Total
,SUM(CASE WHEN EARLYLEAVE = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) TotalEarlyLeave
FROM SUMMARYDATA
),
cte3 as (
SELECT DEPARTMENT, [MONTH], [YEAR], SUM(CASE WHEN TOTAL > 2 THEN 1 ELSE 0 END) LATECOME,
SUM(CASE WHEN TotalEarlyLeave > 1 THEN 1 ELSE 0 END) EARLYLEAVE
FROM cte2
GROUP BY DEPARTMENT, [MONTH], [YEAR]
)
INSERT INTO REPORTDATA (DEPARTMENT, MONTHS, YEARS, RTOTALLOSTTIME, ROT, RLATECOME, REARLYLEAVE)
SELECT cte1.DEPARTMENT, cte1.MONTHS, cte1.YEARS, cte1.RTOTALLOSTTIME, cte1.ROT,
cte3.LATECOME, cte3.EARLYLEAVE
FROM cte1
LEFT JOIN cte3 ON cte3.DEPARTMENT = cte1.DEPARTMENT and cte3.[MONTH] = cte1.[MONTH] and cte3.[YEAR] = cte1.[YEAR]

Advanced SQL with window function

I have Table a(Dimension table) and Table B(Fact table) stores transaction shopper history.
Table a : shopped id(surrogate key) created for unique combination(any of column 2,colum3,column4 repeated it will have same shopper id)
Table b is transaction data.
I am trying to identify New customers and repeated customers for each week, expected output is below.
I am thinking following SQL Statement
Select COUNT(*) OVER (PARTITION BY shopperid,weekdate) as total_new_shopperid for Repeated customer,
for Identifying new customer(ie unique) in same join condition, I am stuck on window function..
thanks,
Sam
You can use the DENSE_RANK analytical function along with aggregate function as follows:
SELECT WEEK_DATE,
COUNT(DISTINCT CASE WHEN DR = 1 THEN SHOPPER_ID END) AS TOTAL_NEW_CUSTOMER,
SUM(CASE WHEN DR = 1 THEN AMOUNT END) AS TOTAL_NEW_CUSTOMER_AMT,
COUNT(DISTINCT CASE WHEN DR > 1 THEN SHOPPER_ID END) AS TOTAL_REPEATED_CUSTOMER,
SUM(CASE WHEN DR > 1 THEN AMOUNT END) AS TOTAL_REPEATED_CUSTOMER_AMT
FROM
(
select T.*,
DENSE_RANK() OVER (PARTITION BY SHOPPER_ID ORDER BY WEEK_DATE) AS DR
FROM YOUR_TABLE T);
GROUP BY WEEK_DATE;
Cheers!!
Tejash's answer is fine (and I'm upvoting it).
However, Oracle is quite efficient with aggregation, so two levels of aggregation might have better performance (depending on the data):
select week_date,
sum(case when min_week_date = week_date then 1 else 0 end) as new_shoppers,
sum(case when min_week_date = week_date then amount else 0 end) as new_shopper_amount,
sum(case when min_week_date > week_date then 1 else 0 end) as returning_shoppers,
sum(case when min_week_date > week_date then amount else 0 end) as returning_amount
from (select shopper_id, week_date,
sum(amount) as amount,
min(week_date) over (partition by shopper_id) as min_week_date
from t
group by shopper_id, week_date
) sw
group by week_date
order by week_date;
Note: If this has better performance, it is probably due to the elimination of count(distinct).

How to get count of a particular row

I have table that contain Id,Date and Status i.e open/close
i just want a result in sql that contain month wise open,close and total count of Id's
e.g In Jan open count 15,close count 5 and total count 20
Use RollUp() and Group By as below:
;WITH T AS
(
SELECT
Id,
DATENAME(MONTH,[Date]) AS [MonthName],
Status
FROM #tblTest
)
SELECT
[MonthName],
[Status],
StatusCount
FROM
(
SELECT
MonthName,
CASE ISNULL(Status,'') WHEN '' THEN 'Total' ELSE Status END AS Status,
Count(Status) AS StatusCount
FROM T
GROUP BY ROLLUP([MonthName],[Status])
)X
WHERE X.MonthName IS NOT NULL
ORDER BY X.[MonthName],X.[Status]
Output:
Note: If required data in single row by month then apply PIVOT
select year(date), month(date),
sum(case when status = 'open' then 1 else 0 end) as open_count,
sum(case when status = 'closed' then 1 else 0 end) as closed_count,
count(*) as total_count
from your_table
group by year(date), month(date)

SSRS: how to get top 3 in order Z to A

I try to get in my diagram the top 3 of the worst value in SSRS:
my Code:
SELECT *
FROM (
Select top 3
intervaldate as Datum
,Name
,teamname as Team
,SUM(case when CounterName = 'Blown away' then calculationUnits else 0 end) as Blown
,Sum(case when CounterName = 'Thrown away' then calculationUnits else 0 end) as Thrown
,Sum(case when CounterName = 'total' then calculationUnits else 0 end) as Total
from Counting
where IntervalDate >= dateadd(day,datediff(day,1,GETDATE()),0)
AND IntervalDate < dateadd(day,datediff(day,0,GETDATE()),0)
and Name in (Select SystemID from tSystemView where SystemViewID = 2)
group by intervaldate, teamName, Name
) c
Expression of the diagram:
=Sum(Fields!Blown.Value + Fields!Thrown.Value) / Sum(Fields!Total.Value) * 100
And I sorted it from highest to lowest
But it does not show me the right order.
If I choose every "Name" then it shows me other value then the top 3:
all Names with value:
top 3:
It's because your top 3 statement is in the SQL while your sort is in the report. Without an order by SQL picks the top 3 random records. Also, unless there is more SQL you are not showing, the outer select is unnecessary. Add an order by <column> desc below your group by.
with Calcs as
(
select intervaldate as Datum,
Name,
TeamName,
SUM(case when CounterName = 'Blown away' then calculationUnits else 0 end) as Blown,
Sum(case when CounterName = 'Thrown away' then calculationUnits else 0 end) as Thrown,
Sum(case when CounterName = 'total' then calculationUnits else 0 end) as Total
from Counting
where IntervalDate >= dateadd(day,datediff(day,1,GETDATE()),0)
AND IntervalDate < dateadd(day,datediff(day,0,GETDATE()),0)
and Name in (Select SystemID from tSystemView where SystemViewID = 2)
group by intervaldate, teamName, Name
)
select b.*
from
(
select a.*, row_number() over (order by (Blown + Thrown)/Total desc) as R_Ord -- Change between ASC/DESC depending on needs
from Calcs a
) b
where R_Ord <=3

Group By Multiple Columns, SUM at the first Group By Column

I am writing a query that groups over two columns. this means, it will put Col1 and Col2 in the same group.
How can I do a SUM of records based on Group Col1 ?
I have this so far: http://sqlfiddle.com/#!3/eada2/1
Thank you
I was able to solve it as follows:
WITH cteActivityIds (activityId, allDocuByActivity)
AS
(SELECT activityId, COUNT(*) AS allDocuByActivity FROM #ER GROUP BY activityId)
SELECT
E.activityId AS [Actiivty ID],
docuType AS [Docu Type],
COUNT(docuType),
CONVERT(DECIMAL(16,2), (COUNT(docuType) * 100.00 / t.allDocuByActivity)) [Total DocuType in Activity],
SUM(CASE WHEN [sent] != '1-1-1900' THEN 1 END) AS [Sent],
SUM(CASE WHEN [approved] != '1-1-1900' THEN 1 END) AS [Approved]
FROM
#ER AS E
INNER JOIN cteActivityIds AS t
ON E.activityId = t.activityId
GROUP BY
E.activityId, docuType, t.allDocuByActivity
Thanks
Here is a solution that, in my opinion, looks a little cleaner - it does not require a join and uses 'partition by' to calculate the individual counts:
WITH activityCounts as (
select
activityId,
docuType,
count(activityId) OVER(PARTITION BY activityId) as activityIdCount,
count(docuType) OVER(PARTITION BY activityId, docuType) as docuTypeCount,
SUM(CASE WHEN [sent] != '1-1-1900' THEN 1 END) OVER(PARTITION BY activityId, docuType) AS [Sent],
SUM(CASE WHEN [approved] != '1-1-1900' THEN 1 END) OVER(PARTITION BY activityId, docuType) AS [Approved]
from ER
)
SELECT
activityId,
docuType,
docuTypeCount,
CONVERT(DECIMAL(16,2), (COUNT(docuTypeCount) * 100.00 / activityIdCount)) as [Total DocuType in Activity],
[Sent],
[Approved]
FROM activityCounts
GROUP BY
activityId,
docuType,
activityIdCount,
docuTypeCount,
[Sent],
[Approved]
Here is a link to sqlfiddle
You just need to put an aggregate function on t.allDocuByActivity
MIN(t.allDocuByActivity) AS [Total DocuType in Activity],
However, since your label is DocuType. Don't you need DISTINCT?