SQL query involving count, group by and substring - sql

I would like to group rows of this table according to dates which form the start of SessionID and for each day, I would like to count how many rows there are for each set of ReqPhone values. Each set of ReqPhone values will be defined by the first four digits of ReqPhone. In other words, I would like to know how many rows there are for ReqPhone starting with 0925, 0927 and 0940, how many rows there are for ReqPhone starting with 0979, 0969 and 0955, etc etc.
I have been trying all kinds of group by and count but still haven't arrived at the right query.
Can anybody enlighten me?
Update:
In my country, the government assigns telecoms phone numbers starting with certain digits. Therefore, if you know the starting digits, you know which telecom someone is using. I am trying to count how many messages are sent each day using each telecoms.

SELECT SUBSTRING(ReqPhone, 1, 4),
DATEADD(DAY,0, DATEDIFF(DAY, 0, SessionID)) AS dayCreated,
COUNT(*) AS tally
FROM yourTable
GROUP BY SUBSTRING(ReqPhone, 1, 4),
DATEADD(DAY, 0, DATEDIFF(DAY, 0, SessionID))

SELECT LEFT(ReqPhone, 4),
DATEADD(DAY,0, DATEDIFF(DAY, 0, SessionID)) AS dayCreated,
COUNT(*) AS tally
FROM yourTable
GROUP BY LEFT(ReqPhone,4),
DATEADD(DAY, 0, DATEDIFF(DAY, 0, SessionID))

This will help you to calculate the count of rows group by the ReqPhone type. This query is working successfully in Oracle DB.
SELECT COUNT(SESSIONID), REQP
FROM (SELECT SESSIONID,SUBSTR(REQPHONE,1,4) AS REQP FROM SCHEMA_NAME.TABLE_NAME)
GROUP BY REQP
Note: Please use the column which is unique in the COUNT expression.

Related

SQL script to with the shown screenshot

I want to write a sql script to as shown in the screenshot image. Thank you.
enter image description here
I've tried MAX() function to aggregate the ESSBASE_MONTH field to make it distinct and display a single month in the output instead of multiple months. I am yet to figure out how to put 0 in any month that EMPID did not perform any sale like in December under "Total GreaterThan 24 HE Account" and "Total_HE_Accounts"
The fields of the table are not very informative however based on screenshot, this is the best answer I could come up with.
Assuming the table name is SALES;
select
ADJ_EMPID,
ESSBASE_MONTH,
MAX(YTD_COUNT) AS YTD_COUNT,
SUM(TOTAL_24) AS TOTAL_24,
SUM(TOTAL_ACC) AS TOTAL_ACC
from SALES
group by
ADJ_EMPID,
ESSBASE_MONTH
The above will aggregate the monthly 'sales' data as expected.
To add the 'missing' rows such as the December, it is possible to do it by doing a union of the above query with a vitural table.
select
MAX(MONTH_NUMBER) AS MONTH_NUMBER,
ADJ_EMPID,
ESSBASE_MONTH,
MAX(YTD_COUNT) AS YTD_COUNT,
SUM(TOTAL_24) AS TOTAL_24,
SUM(TOTAL_ACC) AS TOTAL_ACC
from (
select
1 as MONTH_NUMBER,
*
from SALES
union all
select * from (values
(1, '300014366', 'January', 0, 0, 0),
(2, '300014366', 'Feburary', 0, 0, 0),
-- add the other missing months as required
(11, '300014366', 'November', 0, 0, 0),
(12, '300014366', 'December', 0, 0, 0)
) TEMP_TABLE (MONTH_NUMBER, ADJ_EMPID, ESSBASE_MONTH, YTD_COUNT, TOTAL_24, TOTAL_ACC)
) as AGGREGATED_DATA
group by
ADJ_EMPID,
ESSBASE_MONTH
order by MONTH_NUMBER;
TEMP_TABLE is a vitural tables which contains all the months and sales as zero. There is a special field MONTH_NUMBER added to sort the months in the proper order.
Not the easiest query to understand, the requirement is not exactly feasible either..
Link to fiddledb for a working solution with PostgreSQL 15.

Find Gaps in a single date column SQL Server

Good Day everyone,
I need your help.
I am trying to detect gaps in a single column of the type Date or DateTime in SQL Server.
Say we have a list of schools and each school has many records and there is a field of uploadDate.
So something like that:
My outcome would be something like that:
Thank you all.
You can use lead():
select name, dateadd(day, 1, upload_date), dateadd(day, -1, next_upload_date)
from (select t.*,
lead(upload_date) over (partition by name order by upload_date) as next_upload_date
from t
) t
where next_upload_date <> dateadd(day, 1, upload_date);

Joining multiple tables returning duplicates

I am trying the following select statement including columns from 4 tables. But the results return each row 4 times, im sure this is because i have multiple left joins but i have tried other joins and cannot get the desired result.
select table1.empid,table2.name,table2.datefrom, table2.UserDefNumber1, table3.UserDefNumber1, table4.UserDefChar6
from table1
inner join table2
on table2.empid=table1.empid
inner join table3
on table3.empid=table1.empid
inner join table4
on table4.empid=table1.empid
where MONTH(table2.datefrom) = Month (Getdate())
I need this to return the data without any duplicates so only 1 row for each entry.
I would also like the "where Month" clause at the end look at the previous month not the current month but struggling with that also.
I am a bit new to this so i hope it makes sense.
Thanks
If the duplicate rows are identical on each column you can use the DISTINCT keyword to eliminate those duplicates.
But I think you should reconsider your JOIN or WHERE clause, because there has to be a reason for those duplicates:
The WHERE clause hits several rows in table2 having the same month on a single empid
There are several rows with the same empid in one of the other tables
both of the above is true
You may want to rule those duplicate rows out by conditions in WHERE/JOIN instead of the DISTINCT keyword as there may be unexpected behaviour when some data is changing in a single row of the original resultset. Then you start having duplicate empids again.
You can check if a date is in the previous month by following clause:
date BETWEEN dateadd(mm, -1, datefromparts(year(getdate()), month(getdate()), 1))
AND datefromparts(year(getdate()), month(getdate()), 1)
This statment uses DATEFROMPARTS to create the beginning of the current month twice, subtract a month from the first one by using DATEADD (results in the beginning of the previous month) and checks if date is between those dates using BETWEEN.
If your query is returning duplicates, then one or more of the tables have duplicate empid values. This is a data problem. You can find them with queries like this:
select empid, count(*)
from table1
group by empid
having count(*) > 1;
You should really fix the data and query so it returns what you want. You can do a bandage solution with select distinct, but I would not usually recommend that. Something is causing the duplicates, and if you do not understand why, then the query may not be returning the results you expect.
As for your where clause. Given your logic, the proper way to express this would include the year:
where year(table2.datefrom) = year(getdate()) and
month(table2.datefrom) = month(Getdate())
Although there are other ways to express this logic that are more compatible with indexes, you can continue down this course with:
where year(table2.datefrom) * 12 + month(table2.datefrom) = year(getdate()) * 12 + Month(Getdate()) - 1
That is, convert the months to a number of months since time zero and then use month arithmetic.
If you care about indexes, then your current where clause would look like:
where table2.datefrom >= dateadd(day,
- (day(getdate) - 1),
cast(getdate() as date) and
table2.datefrom < dateadd(day,
- (dateadd(month, 1, getdate()) - 1),
cast(dateadd(month, 1, getdate()) as date)
Eliminate duplicates from your query by including the distinct keyword immediately after select
Comparing against a previous month is slightly more complicated. It depends what you mean:
If the report was run on the 23rd Jan 2015, would you want 01/12/2014-31/12/2014 or 23/12/2014-22/01/2015?

How can I group by day, and still return a datetime?

I want to track the users in my db, when they was created to show it in a awesome chart. Each user has a column "Created" that is the DateTime when they was created. Right down to the time that day.
However, for my chart I dont really care about the time, just the day, month and year. Is there a way I can return a datetime and count when I use datepart as the following:
SELECT datepart(year,Created), datepart(month,Created), datepart(day,Created), COUNT(*) AS COUNT
FROM [dbms].[User]
GROUP BY datepart(year,Created), datepart(month,Created), datepart(day,Created)
This returns three columns for year, month and day. Is there any way I could make it sexy and make it return DateTime (in YYYY/MM/DD format) and the cound?
If you're using SQL Server 2008 or later, you can take advantage of the date data type.
SELECT cast(Created as date), COUNT(*) AS COUNT
FROM [dbms].[User]
GROUP BY cast(Created as date)
If you're using SQL Server 2005 or earlier:
SELECT dateadd(day,datediff(day,0,Created), 0), COUNT(*) AS COUNT
FROM [dbms].[User]
GROUP BY dateadd(day,datediff(day,0,Created), 0)
You can try the following:
SELECT dateadd(day, datediff(day, 0, Created), 0) as date, COUNT(*) AS COUNT
FROM [dbms].[User]
GROUP BY dateadd(day, datediff(day, 0, Created), 0)
This will group you users by the creation date without time and will works on each versions of SQL Server. Among this, the Dateadd operation is more faster that casting...

In single select statement count number of orders within several time ranges

Thanks in advance for any thoughts, advice, and suggestions!
System: SQL Server 2008 R2
I need to count for a given customer the number of repurchases within several different time intervals (date ranges), and display these counts in a single table. I get this working with several subsequent common table expressions (cte) which I finally join together. This way, however, is cumbersome and rather inefficient (in terms of performance speed).
The SQL code I expected to be shortest and fastest, however, does not work for several reasons and will return error messages like
“ the subqueries (Select (count …….) will return several values and hence “cannot be used as an expression”
or
Another error message is: “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.”
Please find below a sample table (WDB), the desired result table (WDB_result) and the SQL code that need improvement. Thanks a lot to everyone who may help!
Sample WDB Table:
CustomerID: customer ID
InNo: invoice number
OrderDate: order date
Result table WDB_result:
Columns
A) total number of repurchases
B) number of repurchases within the first 3 months
C) number of repurchases within the first 6 months
D) number of repurchases within the first 12 months
E) number of repurchases with last 3 months
F) number of repurchases with last 6 months
G) number of repurchases with last 12 months
Sample SQL Code to calculate columns A, B, und E:
SELECT
CustomerID
, COUNT(InNo) OVER (PARTITION by CustomerID) -1) as Norepurchases_Total
, (SELECT (COUNT(InNo) OVER (PARTITION by CustomerID) -1) as Count3
FROM WDB
WHERE OrderDate between MIN(OrderDate) and DATEADD(month, 3, MIN(OrderDate))
) as Norepurchases_1st_3months
, (SELECT (COUNT(InNo) OVER (PARTITION by CustomerID) -1) as Count3
FROM WDB
WHERE OrderDate between MAX(OrderDate) and DATEPART(y, DATEADD(m, -3, getdate()))
) as NoRepurchases_Last_3months
FROM WDB;
Typically what I would do in a situation like this is something like
SELECT CustormerID,
SUM(
CASE
WHEN OrderDate > #ThreeMonthsAgo AND OrderDate <= #CurrentDate
1
ELSE 0
END
) InLast3Months,
SUM(
CASE
WHEN OrderDate > #SixMonthsAgo AND OrderDate <= #ThreeMonthsAgo
1
ELSE 0
END
) InLast3To6Months,
...
FROM YourTable
GROUP BY CustomerID
This will alow you to determine the buckets beforehand as variables, as shown, and then count how many items falls in which buckets.
This is a very interesting query and I think what you're after can be achieved if you read over this stackoverflow article on multiple aggregate functions.
Applying the same concept as is used in this question should solve your problem.