Counting records on multiple conditions - sql

My query is to count the number of transactions that are happened in the tables. Below is my query:
select tt.transaction_key, tt.description, t.mode, count(t.TransactionType) as Frequency
from transaction_names tt left join
transaction_report_data t
on tt.transaction_key = t.TransactionType and
t.created >='2017-04-11' and t.created <= '2018-04-13'
group by tt.transaction_key, tt.description, t.mode;
I also need the count/frequency for the number of transactions which are successful only or which has t.status = 'success'.
Please help how can I adjust this 'where' clause to count this type of records also.
Thanks in advance.

You can do a case with aggregate like below
select
tt.transaction_key,
tt.description,
t.mode,
count(t.TransactionType) as Frequency,
Sum(case when t.status='success' then 1 else 0 end) as SuccessfulTransactions
from transaction_names tt left join
transaction_report_data t
on tt.transaction_key = t.TransactionType and
t.created >='2017-04-11' and t.created <= '2018-04-13'
group by tt.transaction_key, tt.description, t.mode;

Try this
SELECT
tt.transaction_key,
tt.[Description],
t.mode,
COUNT(t.TransactionType) AS Frequency,
Success = SUM(CASE WHEN T.[Status]='Success' THEN 1 ELSE 0 END)
FROM transaction_names tt
LEFT JOIN transaction_report_data t
ON tt.transaction_key = t.TransactionType
AND t.created >= '2017-04-11'
AND t.created <= '2018-04-13'
GROUP BY
tt.transaction_key,
tt.[Description],
t.mode;

select tt.transaction_key, tt.description, t.mode, count(t.TransactionType) as Frequency
from transaction_names tt left join
transaction_report_data t
on tt.transaction_key = t.TransactionType and
t.created >='2017-04-11' and t.created <= '2018-04-13'
group by tt.transaction_key, tt.description, t.mode, t.status
having t.status = 'success'

Related

How to use count(‘condition') over(partition by xx) in SQL

Here is the database:
The first table is named Trip and the second table is Users.
CLIENT_ID and DRIVER_ID are foreign keys for USERS_ID in the Users table. I want to find how many orders cancelled by the non-banned driver and non-banned passenger for each day (Trip.Status != 'completed' and Users.Banned ='No').
My code is :
SELECT
t.Request_at AS 'Day',
COUNT(Status != 'completed') OVER (PARTITION BY t.Request_at) AS 'Cancellation Num'
FROM
Trips t
JOIN
Users u1 ON t.Client_Id = u1.Users_Id AND u1.Banned = 'No'
JOIN
Users u2 ON t.Driver_Id = u2.Users_Id AND u2.Banned = 'No'
WHERE
t.Request_at >= '2013-10-01' AND t.Request_at <= '2013-10-03'
GROUP BY
t.Request_at
The results for '2013-10-01' and '2013-10-03' are right(both equal to 1). But it turns wrong at '2013-10-02'. It becomes to 1, but it should be 0. I do not know where is the mistake in my code. Could someone help me?
I suspect that you really want conditional aggregation, not a window function:
SELECT t.Request_at AS Day,
SUM(CASE WHEN Status <> 'completed' THEN 1 ELSE 0 END) as num_cancellations
FROM Trips t JOIN
Users u1
ON t.Client_Id = u1.Users_Id AND
u1.Banned = 'No' JOIN
Users u2
ON t.Driver_Id = u2.Users_Id AND u2.Banned = 'No'
WHERE t.Request_at >= '2013-10-01' AND t.Request_at <= '2013-10-03'
GROUP BY t.Request_at;
Note: Only use single quotes for string and date constants. Don't use them for column aliases.
Try this:
SELECT
t.Request_at AS 'Day',
COUNT(case when Status != 'completed' then 1 else null end) OVER (PARTITION BY t.Request_at) AS 'Cancellation Num'
FROM
Trips t
JOIN
Users u1 ON t.Client_Id = u1.Users_Id AND u1.Banned = 'No'
JOIN
Users u2 ON t.Driver_Id = u2.Users_Id AND u2.Banned = 'No'
WHERE
t.Request_at >= '2013-10-01' AND t.Request_at <= '2013-10-03'
GROUP BY
t.Request_at

UPDATE all records from existing SELECT query

I have query to select data from related tables.
SELECT
s.id,
CASE
WHEN count(DISTINCT e.id) <> 0
THEN count(DISTINCT o.id) / count(DISTINCT e.id)
END OrdersAverageNumber
FROM
[School] s
JOIN
[SchoolStore] ss ON ss.SchoolId = s.Id
JOIN
[Event] e ON e.SchoolId = ss.SchoolId
AND e.IsDeleted = 0
AND e.Status = 1
AND e.Date >= #startDate
AND e.Date <= #endDate
JOIN
[Order] o ON o.EventId = e.id
AND o.OrderStatus = 1
AND o.CreatedDate >= #startDate
AND o.CreatedDate <= #endDate
GROUP BY
s.id;
But I can't understand what I need to change to update all OrdersAverageNumber records in School table with values from selection above.
You can use update:
with q as (< your query here >)
update s
set OrdersAverageNumber = q.OrdersAverageNumber
from school s join
q
on s.id = q.id;

SQL optimization GROUP BY same table, same column

I have this GROUP BY query where I need to select some records from TABLE_1 and aggregate them.
The SELECTs are similar but I need to aggregate LON and BHAM separately as they are two different concepts but reside in same table.
My question is can I write the below differently in oracle that will optimize the performance of the query?
SELECT *
FROM (
( SELECT /*+ full(t1) */
t3.custId AS ID,
t2.secID AS SEC_ID,
t1.org_date AS SETT_DATE,
SUM(t1.amount) AS TOTAL
FROM test.TABLE_1 t1
INNER JOIN test.TABLE_2 t2 on t2.a_code = t1.a_code and t2.c_code = t1.c_code and t2.expiry_date > trunc(sysdate)
INNER JOIN test.TABLE_3 t3 on t3.account_id = t1.account_id
WHERE t1.city = 'LON'
AND t1.amount < 50000 and t1.amount > -50000
GROUP BY t3.custId, t2.secID, t1.org_date
)
UNION ALL
( SELECT /*+ full(t1) */
t3.custId AS ID,
t2.secID AS SEC_ID,
t1.org_date AS SETT_DATE,
SUM(t1.amount) AS TOTAL
FROM test.TABLE_1 t1
INNER JOIN test.TABLE_2 t2 on t2.a_code = t1.a_code and t2.c_code = t1.c_code and t2.expiry_date > trunc(sysdate)
INNER JOIN test.TABLE_3 t3 on t3.account_id = t1.account_id
WHERE t1.city = 'BHAM'
AND t3.alias = 'ABC'
AND t1.amount < 50000 and t1.amount > -50000
GROUP BY t3.custId, t2.secID, t1.org_date
)
)
ORDER BY ID, SEC_ID,
CASE WHEN SETT_DATE < TRUNC(sysdate) THEN trunc(sysdate) ELSE TRUNC(SETT_DATE) end
Remove union all and everything after, remove outer select, write where clause like here:
where -50000 < t1.amount and t1.amount < 50000
and (t1.city = 'LON' or (t1.city = 'BHAM' and t3.alias = 'ABC'))
You need to add the city column into the group by, and update the where clause to get both sets of rows, e.g.:
SELECT custid,
sec_id,
sett_date,
total
FROM (SELECT t3.custid AS id,
t2.secid AS sec_id,
CASE
WHEN t1.org_date < trunc(SYSDATE) THEN
trunc(SYSDATE)
ELSE
trunc(t1.org_date)
END AS sett_date,
t1.city,
SUM(t1.amount) AS total
FROM test.table_1 t1
INNER JOIN test.table_2 t2
ON t2.a_code = t1.a_code
AND t2.c_code = t1.c_code
AND t2.expiry_date > trunc(SYSDATE)
INNER JOIN test.table_3 t3
ON t3.account_id = t1.account_id
WHERE (t1.city = 'LON' OR (t1.city = 'BHAM' AND t3.alias = 'ABC'))
AND t1.amount < 50000
AND t1.amount > -50000
GROUP BY t3.custid,
t2.secid,
CASE
WHEN t1.org_date < trunc(SYSDATE) THEN
trunc(SYSDATE)
ELSE
trunc(t1.org_date)
END)
ORDER BY id,
sec_id,
sett_date;
However, I'm surprised you need both rows, since you can't tell which belongs to which city. I suspect you need to include the city (and maybe alias) columns into the final results.

Sub select SQL query using where and groupby

When I try below code in SQL Server,
SELECT
dbo.Category.CatNo as Category,
dbo.Category.Categaory as Name,
(select SUM(dbo.SALES.SELLINC) where (dbo.SALES.DATE BETWEEN '2016-07-17' AND '2016-07-23')) AS ActualSales,
(select SUM(dbo.SALES.SELLINC) where (dbo.SALES.DATE BETWEEN '2015-07-19' AND '2015-07-25')) AS LastYrVariance,
(select SUM(dbo.SALES.SELLINC) where (dbo.SALES.DATE BETWEEN '2016-01-01' AND '2016-09-05')) AS YrToDateActual,
(select SUM(dbo.SALES.SELLINC) where (dbo.SALES.DATE BETWEEN '2015-01-01' AND '2015-09-05')) AS LastYrToDateActual
FROM dbo.Category INNER JOIN
dbo.Dissection ON dbo.Category.CatNo = dbo.Dissection.CatNo INNER JOIN
dbo.Division ON dbo.Dissection.DivNo = dbo.Division.ID INNER JOIN
dbo.Departments ON dbo.Dissection.DeptNo = dbo.Departments.DeptID INNER JOIN
dbo.SALES ON dbo.Dissection.DissNo = dbo.SALES.CODE
WHERE (dbo.SALES.BRN = 1)
GROUP BY dbo.Category.CatNo, dbo.Category.Categaory
ORDER BY dbo.Category.CatNo
I get below error message,
Msg 8120, Level 16, State 1, Line 2
Column 'dbo.Category.CatNo' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY
clause.
Any help please?
The subqueries have a select clause, with a Sum() function which attempts to Sum the values from a column of a table that is not mentioned in the Subquery. (The subqueries have no FROM clause). These subqueries should not be subqueries, they just need to be Sum() expressions.
And you should check into using aliases to simplify your SQL scripts.
SELECT c.CatNo Category, c.Categaory Name,
sum(case when s.Date between '2016-07-17' and '2016-07-23'
then s.SELLINC else 0 end) ActualSales,
sum(case when s.Date between '2015-07-25' and '2015-07-19'
then s.SELLINC else 0 end) LastYrVariance,
sum(case when s.Date between '2016-01-01' and '2016-09-05'
then s.SELLINC else 0 end) YrToDateActual,
sum(case when s.Date between '2015-01-01' AND '2015-09-05'
then s.SELLINC else 0 end) LastYrToDateActual
FROM dbo.Category c
join dbo.Dissection d on d.CatNo = c.CatNo
join dbo.Division v on v.Id = d.DivNo
join dbo.Departments p on p.DeptID = d.DeptNo
join dbo.SALES s on s.code = d.DissNo
WHERE s.BRN = 1
GROUP BY c.CatNo, c.Categaory
ORDER BY c.CatNo
to generate date range dynamically, as requested in comment, use datediff and dateAdd functions: I'm not sure what you meant by previous week (31 week 2016) or Last year same week (31 week 2015), so if this is not right, you can modify to correct.
SELECT c.CatNo Category, c.Categaory Name,
sum(case when s.Date between
dateAdd(week, datediff(week, 0, getdate())-52, 0)
and dateAdd(week, datediff(week, 0, getdate()), 0)
then s.SELLINC else 0 end) ActualSales,
sum(case when s.Date between '2015-07-25' and '2015-07-19'
then s.SELLINC else 0 end) LastYrVariance,
sum(case when s.Date between '2016-01-01' and '2016-09-05'
then s.SELLINC else 0 end) YrToDateActual,
sum(case when s.Date between '2015-01-01' AND '2015-09-05'
then s.SELLINC else 0 end) LastYrToDateActual
FROM dbo.Category c
join dbo.Dissection d on d.CatNo = c.CatNo
join dbo.Division v on v.Id = d.DivNo
join dbo.Departments p on p.DeptID = d.DeptNo
join dbo.SALES s on s.code = d.DissNo
WHERE s.BRN = 1
GROUP BY c.CatNo, c.Categaory
ORDER BY c.CatNo
I cant find a reason to generate that error in your query. Between you can simply those sub-queries by using CASE statements
SELECT dbo.category.catno AS Category,
dbo.category.categaory AS NAME,
Sum(CASE WHEN dbo.sales.date BETWEEN '2016-07-17' AND '2016-07-23' THEN dbo.sales.sellinc END) AS ActualSales,
Sum(CASE WHEN dbo.sales.date BETWEEN '2015-07-19' AND '2015-07-25' THEN dbo.sales.sellinc END) AS LastYrVariance,
Sum(CASE WHEN dbo.sales.date BETWEEN '2016-01-01' AND '2016-09-05' THEN dbo.sales.sellinc END) AS YrToDateActual,
Sum(CASE WHEN dbo.sales.date BETWEEN '2015-01-01' AND '2015-09-05' THEN dbo.sales.sellinc END) AS LastYrToDateActual
FROM dbo.category
INNER JOIN dbo.dissection
ON dbo.category.catno = dbo.dissection.catno
INNER JOIN dbo.division
ON dbo.dissection.divno = dbo.division.id
INNER JOIN dbo.departments
ON dbo.dissection.deptno = dbo.departments.deptid
INNER JOIN dbo.sales
ON dbo.dissection.dissno = dbo.sales.code
WHERE ( dbo.sales.brn = 1 )
GROUP BY dbo.category.catno,
dbo.category.categaory
ORDER BY dbo.category.catno
can you try with the below query.
SELECT Category.CatNo as Category, Category.Categaory as Name,
(select SUM(SALES.SELLINC) where (SALES.DATE BETWEEN '2016-07-17' AND '2016-07-23')) AS ActualSales,
(select SUM(SALES.SELLINC) where (SALES.DATE BETWEEN '2015-07-19' AND '2015-07-25')) AS LastYrVariance,
(select SUM(SALES.SELLINC) where (SALES.DATE BETWEEN '2016-01-01' AND '2016-09-05')) AS YrToDateActual,
(select SUM(SALES.SELLINC) where (SALES.DATE BETWEEN '2015-01-01' AND '2015-09-05')) AS LastYrToDateActual
FROM dbo.Category INNER JOIN
dbo.Dissection ON Category.CatNo = Dissection.CatNo INNER JOIN
dbo.Division ON Dissection.DivNo = Division.ID INNER JOIN
dbo.Departments ON Dissection.DeptNo = Departments.DeptID INNER JOIN
dbo.SALES ON Dissection.DissNo = SALES.CODE
WHERE (SALES.BRN = 1)
GROUP BY Category.CatNo, Category.Categaory
ORDER BY Category.CatNo

Select inside CASE THEN

I need to select the project rate or shift rate that has the effective date less than today.
SELECT
CASE
WHEN ISNULL(s.rate,0) = 0
THEN SELECT TOP 1 pr.rate FROM ProjectRates pr WHERE (pr.projectID = p.ID) AND (pr.effectiveDate < GETDATE()) ORDER BY pr.effectiveDate DESC
--p.rate
ELSE SELECT TOP 1 sr.rate FROM ShiftRates sr WHERE (sr.shiftID = s.ID) AND (sr.effectiveDate < GETDATE()) ORDER BY pr.effectiveDate DESC
--s.rate
END AS rate
FROM Projects p
INNER JOIN Shifts s ON (p.ID = s.projectID)
WHERE (p.ID = #projectID)
Please note that this code snippet is part of a larger stored proc and thus it must be within a CASE statement.
Subqueries need parentheses:
SELECT (CASE WHEN ISNULL(s.rate, 0) = 0
THEN (SELECT TOP 1 pr.rate
FROM ProjectRates pr
WHERE (pr.projectID = p.ID) AND (pr.effectiveDate < GETDATE())
ORDER BY pr.effectiveDate DESC
)
ELSE (SELECT TOP 1 sr.rate
FROM ShiftRates sr
WHERE (sr.shiftID = s.ID) AND (sr.effectiveDate < GETDATE())
ORDER BY pr.effectiveDate DESC
) --s.rate
END) AS rate
FROM Projects p INNER JOIN
Shifts s
ON p.ID = s.projectID
WHERE p.ID = #projectID;