SQL count records depending on criteria - sql

I have a table which has account information for each individual working day. Each record shows the balance on the account for that particular day. I need to create a field that has a running count on how many days it has been since the balance on that particular account was zero.
For example: I have an account which is number 00000001. It was opened a week ago. The database has created a record for the account for last Tuesday, Wednesday, Thursday, Friday and Monday. The account did not have a balance until Friday and the balance was the same for Monday. I want the field to show '2' as a result. Further to this if the balance drops to '0' today, I need the count to reset on the next record and start again if the account has a balance the following day. There are several accounts in this table so I need this to work for each one individually.
Below is as far as I have got:
SELECT
pos.EffDate,
cus.CNA1,
pos.ACNO,
pos.CCY,
pos.LDBL,
pos.LDBLUSD,
MIN(pos3.effdate) AS 'First Post Date',
pos3.Balcount
FROM[dbo].[Account] AS pos
JOIN [dbo].[Customer] AS cus ON ((pos.CNUM=cus.CUST_NO) AND (cus.effdate=pos.effdate))
LEFT JOIN (SELECT pos2.effdate, pos2.ACNO, SUM(CASE pos2.LDBL WHEN 0 THEN 0 ELSE 1 END) AS 'Balcount' FROM [dbo].[Account] AS pos2 GROUP BY pos2.ACNO, pos2.Effdate HAVING pos2.effdate BETWEEN pos2.effdate AND MIN(pos2.effdate)) pos3 ON pos3.ACNO = pos.ACNO
WHERE pos.effdate >='1 Dec 2015' AND pos.Effdate <'30 Dec 2015'
AND pos.srcsys = 'MP_UK'
AND pos.LDBL <= 0
AND pos.CNUM <> '000020'
AND pos.intbear <> 'N'
AND pos.blockdeb IS null
GROUP BY pos.EffDate,cus.CNA1,pos.ACNO,pos.CCY,pos.LDBL,pos.LDBLUSD, pos3.Balcount
ORDER BY 1,2,3
If you need me to clarify anything please let me know. All help is greatly appreciated.
Thanks,
Ben

Basically, you want to group the data, based on the number of time the account is zero before a given row. Then, within each group, you want to enumerate the records.
In SQL Server 2012+, you can do these things with window functions. I am not sure exactly what your sample query has to do with the question, but here is the basic idea:
select a.*, row_number() over (partition by cust_no, grp order by eff_date) as seqnum
from (select a.*,
sum(case when balance = 0 then 1 else 0 end) over
(partition by cust_no order by eff_date) as grp
from Account a
) a;
In earlier versions of SQL Server, you can do something very similar using apply.

Related

Total hours worked for employees in 2018 and 2019

I am new to stackoverflow and new to sql. I have employee timesheets which has a unique id and hours works by employees. I was wondering if theres a way to calculate the sum of the hours for each employee in 2018.
I dont know if this query is too basic but what i have so far is this:
select distinct PersonId, SUM(reghours) as '2018'
from TimeSheetsView
where left(yearweek,4)='2018'
group by PersonId, reghours
If you wanted to sum up both 2018 and 2019 in their own columns you could use a case statement to target those specific records in 2018 and 2019 placing them in their own column. You don't need a distinct with the group by either and like Mitch said you don't need that reghours it will split aggregation.
In the THEN piece it will sum up that field and ELSE is 0 so it won't obviously sum up any other rows that don't meet that condition.
Select PersonId
, SUM(CASE WHEN left(yearweek,4)='2018' THEN reghours ELSE 0 END) as '2018_RegHours'
, SUM(CASE WHEN left(yearweek,4)='2019' THEN reghours ELSE 0 END) as '2019_RegHours'
from TimeSheetsView
where left(yearweek,4) IN ('2018', '2019')
group by PersonId

SQL help to display no. of openings for all branches for each month of a year

Hi I need to generate a SSRS report to show how many centers got opened for each month in a calendar year under each branch. report will have 13 columns, first column being all the branches in each row and remaining 12 columns will have months of an year as header. I'm trying to get a result of each branch having no. of openings per month, so I can feed SSRS to display in tabular format. If a branch doesnt have any openings for any month, I need to display 0.
Branch table
=============
Branchid
Branchname
CenterOpen table
================
CenterOpenID
BranchID
CenterOpenDate
below is the SQL I had written
WITH months(MonthNumber) AS (
SELECT
1
UNION ALL
SELECT
MonthNumber + 1
FROM
months
WHERE
MonthNumber < 12
),
cteBranch(BranchID, BranchName, TargetOpenDate, Month, Count) as (
SELECT
B.BranchID,
B.BranchName,
CS.TargetOpenDate,
MONTH(CS.TargetOpenDate) as Month,
count(Month(CS.TargetOpenDate)) as Count
FROM
Branch B
left join goal.CenterOpenSchedule CS ON CS.BranchID = B.BranchID
GROUP BY
B.BranchID,
B.BranchName,
CS.TargetOpenDate,
MONTH(CS.TargetOpenDate)
)
select
*
from
months
cross join cteBranch
order by
BranchID asc,
MonthNumber asc
If I use cross join, months are repeating for each branch, how to resolve this? your help is highly appreciated.
Not sure which database you are on.
There are different ways to extract month/year from date.
Based on your example SQL, I'm going to use MONTH()
select branchName,
count(case when month(centerOpenDate) = 1 then branchId end) Jan_Count
...
...
count(case when month(centerOpenDate) = 12 then branchId end) Dec_Count
from Branch b
join CenterOpen co
on (b.BranchId = co.BranchId)
where year(centerOpenDate) = <your year filter>
group by branchName
This will take care of your below requirements:
" first column being all the branches in each row and remaining 12 columns will have months of an year as header."
and also -
"If a branch doesnt have any openings for any month, I need to display 0."
Your question is not explicit, but you seem to want a single year -- so you need to filter on the year.
The rest is basically conditional aggregation:
select b.branchName,
sum(case when month(co.centerOpenDate) = 1 then 1 else 0 end) as jan,
sum(case when month(co.centerOpenDate) = 2 then 1 else 0 end) as feb,
. . .
sum(case when month(co.centerOpenDate) = 12 then 1 else 0 end) as dec
from Branch b join
CenterOpen co
on b.BranchId = co.BranchId
where year(co.centerOpenDate) = #year
group by b.branchName

How to filter Users that meet CASE criteria without nesting WHERE in SQL?

Right now I have a query that lets me know which users didn't make a purchase 12 months prior to becoming members. These users have MEM_PRE_12=0 and I want to filter off those users more natively using SQL partitions rather than always putting rudimentary WHERE criteria.
Here is the SQL I use to find the users I want/don't want.
SELECT SUM(CASE WHEN DATE <= DATEADD(month, -12, U.INSERTED_AT) THEN 1 ELSE 0 END) AS MEM_PRE_12, I.CLIENTID, I.INSTALLATIONID
FROM <<<My_Joined_Tables>>>
GROUP BY I.CLIENTID, I.INSTALLATIONID
HAVING MEM_PRE_12 != 0
ORDER BY MEM_PRE_12
After this I'm going to have to go back and say where I.CLIENTID in the above nested query and select the actual information I want from users who made purchases greater than their insertion date.
How can I do this without so much nesting of all these joined tables?
If you want the detailed rows for customers who made a purchase in the last 12 months, you can use window functions:
with q as (
<whatever your query logic is>
)
select q.*
from (select q.*,
SUM(CASE WHEN DATE <= DATEADD(month, -12, U.INSERTED_AT) THEN 1 ELSE 0 END) over (partition by CLIENTID, INSTALLATIONID) as AS MEM_PRE_12
from q
) q
where mem_pre_12 > 0;

How to search for count of customers in SQL database?

I have an SQL table named "accounts" with the following columns:
registration_date
account_id
and have another SQL table named "revenue" with the following columns:
account_id
revenue_month
sales_revenue
What I am trying to achieve is to get the following:
Get a count of customers that registered between Jan and Dec 2017, and a count of how many of them bought something in 2017 (ie. sales_revenue more than 0).
I am very new to SQL and I tried the following but I couldn't do it.
SELECT COUNT account_id
FROM accounts
WHERE registration_date BETWEEN #01/01/2017# AND #12/31/2017#;
should give me the number of accounts that were registered in 2017?
and then
SELECT COUNT account_id
FROM revenue
WHERE sales_revenue > 0;
should give me the number of accounts that had a revenue of more than 0?
What am I missing? I would appreciate any help.
THANKS!
Try this out:
select count(account_id) as total,
sum(case when sales_revenue > 0 then 1 else 0 end) as sales_rev
FROM accounts
WHERE registration_date BETWEEN #01/01/2017# AND #12/31/2017#;
Let me know in case of any queries.
SELECT
COUNT(DISTINCT accounts.account_id)
FROM
accounts, revenue
WHERE
accounts.registration_date BETWEEN #01/01/2017# AND #12/31/2017#
AND
revenue.revenue_month BETWEEN #01/2017# AND #12/2017#
AND
accounts.account_id = revenue.account_id
AND
sales_revenue > 0
Oracle (again). Your database might use different functions.
Presuming that REGISTRATION_DATE is of a DATE datatype (and yes, it should be), then this might do the job:
select count(*)
from accounts
where extract(year from registration_date) = 2017;
The same goes for revenue - presuming that REVENUE_MONTH is DATE. If it is not, what is it?
select count(distinct account_id)
from revenue
where extract(year from revenue_month) = 2017
having sum(sales_revenue) > 0;
Try the following
Get a count of customers that registered between Jan and Dec 2017
SELECT COUNT (account_id)
FROM accounts
WHERE registration_date BETWEEN '01-JAN-2017' AND '12-DEC-2017'
and a count of how many of them bought something in 2017 (ie. sales_revenue more than 0).
SELECT COUNT (account_id)
FROM revenue
WHERE sales_revenue > 0
AND registration_date BETWEEN '01-JAN-2017' AND '12-DEC-2017'
The above is Oracle, your database would be something similar.
If you post a SQLFiddle, sample data and expected results, you'll get better answers...
You are missing a join.
Table accounts tells you who registered in the date range you care about, and table revenue tells you what they bought.
Not every account bought something, so you need an outer join.
As you only want to count the number of accounts that bought something, rather than the number of transactions, you have to use a distinct count. Not supported on every platform.
You want something like:
SELECT COUNT (a.*), count(distinct r.account_id)
FROM accounts a
outer join revenue r
on a.account_id = r.account_id
WHERE a.registration_date BETWEEN #01/01/2017# AND #12/31/2017#
and r.revenue_Month between '01/2017' and '12/2017'
This gives you all customers who registered in 2017 along with the information whether they bought something in 2017:
select
account_id,
case when exists
(
select *
from revenue r
where r.account_id = a.account_id
and r.sales_revenue > 0
and r.revenue_month like '%2017%'
) then 1 else 0 end as has_bought_in_2017
from accounts a
where year(registration_date) = 2017;
(You may want to change the LIKE clause; I don't know how your revenue_month is built.)
Now use this query to get the counts:
select
count(*) as registered_in_2017,
sum(has_bought_in_2017) as and_have_bought_in_2017
from (<above query>) q;
SELECT COUNT(account_id)
FROM accounts
WHERE registration_date BETWEEN '01/01/2017' AND '12/31/2017';
This will give you the count of account id who has registered in between 01/01/2017 AND 12/31/2017
SELECT COUNT(account_id)
FROM revenue
WHERE sales_revenue > 0;
This will give you the number of account id's who has sales_revenue greater than zero.
If you want the number of accounts between 01/01/2017 AND 12/31/2017 and
sales_revenue > 0 then:
select count(account_id)
from accounts a,revenue r
where a.registration_date BETWEEN '01/01/2017' AND '12/31/2017'
and r.sales_revenue > 0;

using count in a subquery and getting errors

i have line by line data in a table and i need to net of cancellations from sales and produce a report grouping on a scheme identifier. i.e i need to find all the sales and subtract all the cancellatsion to prduce a net sales figure.
i am trying to use the query below but i'm getting errors.
select insscheme, ((select count(quote_id) where (sale = '1')) - (select count(quote_id) where cancellation = '1')) as sales from policys
group by insscheme
order by insscheme
and i'm getting the error
Column 'policys.Sale' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Can anyone help me out with this?
You don't need any sub queries here. Just use COUNT and CASE.
SELECT insscheme,
COUNT(CASE WHEN sale = '1' AND cancellation <> '1' THEN 1 END) AS sales
FROM policys
GROUP BY insscheme
ORDER BY insscheme
I have assumed above that cancellation is not nullable. If it is use
COUNT(CASE WHEN sale = '1' THEN 1 END) -
COUNT(CASE WHEN cancellation = '1' THEN 1 END) AS sales
Perhaps this might work.
select insscheme, SUM(sale) - SUM(cancellation) as NetSales
from policys
group by insscheme
I don't see what the quote_id column has to do with your query. Are you querying one table or several? It would help if you could show us what your schema looks like with a brief discussion of your table layout.