select query output not as expected - sql

i need one single query which will give result like the one i give below
createddate recordcount acceptdate submitdate createddate
27-MAR-16 24 36 11
28-MAR-16 79 207 58
for reference i am providing some queries which i want to merge into one single query
select trim(date_created) createddate,count(*) recordcount
from man
where status IN ('CREATED')and date_created>sysdate-15
group by trim(date_created) ORDER BY TO_DATE(createddate,'DD/MM/YYYY');
this query will result like the following.
createddate recordcount
27-MAR-16 11
28-MAR-16 58
the second query
select trim(DATE_SUB) submitdate,count(*) recordcount
from man
where status IN ('SUBMITTED')and DATE_SUB>sysdate-15
group by trim(date_sub) ORDER BY TO_DATE(submitdate,'DD/MM/YYYY');
result of this query is like
submitdate recordcount
27-MAR-16 36
28-MAR-16 207
and the third query is like -
select trim(DATE_PUB) acceptdate,count(*) recordcount
from man
where status IN ('ACCEPTED')and DATE_PUB>sysdate-15
group by trim(DATE_PUB) ORDER BY TO_DATE(acceptdate,'DD/MM/YYYY');
acceptdate recordcount
27-MAR-16 24
28-MAR-16 79
how can i merger these three query so that i can get count for all in single query?which will give me result like
createddate recordcount acceptdate submitdate createddate
27-MAR-16 24 36 11
28-MAR-16 79 207 58

Your first query where clause has date but second query where clause has DATE_P.
Try like this
SELECT Trim(date) createddate,
COUNT(*) recordcount,
SUM(case when status = 'A' then 1 else 0 end) as a,
SUM(case when status = 'S' then 1 else 0 end) as s,
SUM(case when status = 'C' then 1 else 0 end) as c,
SUM(case when status = 'R' then 1 else 0 end) as r
FROM man
WHERE status IN ('A','S','C','R')and date >sysdate-15
GROUP BY trim(date) ORDER BY createddate;

You seem to want to get counts for each status type, for each day. The first step is generate all the dates you're interested in, which you can do with:
select trunc(sysdate) + 1 - level as dt
from dual
connect by level <= 15;
You can then (outer) join to your actual table where any of the three date columns match a generated date, and expand your case conditions to check which one you're looking at:
with t as (
select trunc(sysdate) + 1 - level as dt
from dual
connect by level <= 15
)
select t.dt,
count(*) as recordcount,
count(case when status = 'ACCEPTED' and trunc(m.date_pub) = t.dt
then 1 end) as acceptdate,
count(case when status = 'SUBMITTED' and trunc(m.date_sub) = t.dt
then 1 end) as submitdate,
count(case when status = 'CREATED' and trunc(m.date_created) = t.dt
then 1 end) as createddate
from t
left join man m
on (m.date_pub >= t.dt and m.date_pub < t.dt + 1)
or (m.date_sub >= t.dt and m.date_sub < t.dt + 1)
or (m.date_created >= t.dt and m.date_created < t.dt + 1)
group by t.dt
order by t.dt;
I've used range checks for the join conditions - it isn't clear if all your date columns are set at midnight, but it's safer to assume they might have other times and you cant everything from the matching day.
Each of the three count results is now only of those rows which match the status and where the specific date column matches, which I think is what you want. I've used trunc() here instead of a range comparison, as it doesn't have the potential performance penalty you can see in the where clause (from it potentially stopping an index being used).
This may throw out your recordcount though, depending on your actual data, as that will include rows that now might not match any of the case conditions. You can repeat the case conditions, or use an inline view to calculate the total of the three individual counts, depending on what you want it to include and what will be the easiest for you to maintain. If those are the only three statuses in your table then it may be OK with count(*) but check it gets the value you expect.

Related

How to sum count on specific columns in sql

I want to calculate specific sum of counts
select is_known_bot, count(*)
FROM "public"."bus_request"
where app_name = 'xxxxxx' and event_type <> 'browser_js'
and is_known_bot <>''
and date <= GETDATE() and date>= GETDATE()-14
group by is_known_bot
order by is_known_bot asc
I am getting the below table:
is_known_bot count
good 2
bad 3
Human 7
in the end, i want to get the below table:
is_known_bot count
bot 5
Human 7
You can use CASE instead the column is_know_bot
Case when is_know_bot = 'Human' then is_know_bot else 'Bot' end

Count total number of records based on answers

i have a result which displays two answers and i want to result the total number of counts by each record. With my query i display two answers (like and dislike). i want to count the total number of like and also the total number of dislike
SELECT (CASE WHEN log_time <= rdate_up THEN 'like' ELSE 'dislike' end )as answer
FROM dbo.users
Considering the algorithm you gave us to validate if value is a like or dislike is
log_time <= rdate_up
Then you could use union and count to separate them.
select count(*) as count_of_like
from dbo.users
where log_time <= rdate_up
union
select count(*) as count_of_dislike
from dbo.users
where log.time > rdate_up;
You can do this another way using CASE. This will be faster because it only hits the base table once.
select sum(case when log_time <= rdate_up then 1 end) as LikeCount
, SUM(case when log.time > rdate_up then 1 end) as DislikeCount
from dbo.users

More efficient way of grouping rows by hour (using a timestamp)

I'm trying to show a log of daily transactions that take place. My current method is embarrassingly inefficient and I'm sure there is a much better solution. Here is my current query:
select ReaderMACAddress,
count(typeid) as 'Total Transactions',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '05:00:00' and '11:59:59' THEN 1 ELSE 0 END) as 'Morning(5am-12pm)',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '12:00:00' and '17:59:59' THEN 1 ELSE 0 END) as 'AfternoonActivity(12pm-6pm)',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '18:00:00' and '23:59:59' THEN 1 ELSE 0 END) as 'EveningActivity(6pm-12am)',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '00:00:00' and '04:59:59' THEN 1 ELSE 0 END) as 'OtherActivity(12am-5am)'
from Transactions
where ReaderMACAddress = '0014f54033f5'
Group by ReaderMACAddress;
which returns the results:
ReaderMACAddress Total Transactions Morning(5am-12pm) AfternoonActivity(12pm-6pm) EveningActivity(6pm-12am) OtherActivity(12am-5am)
0014f54033f5 932 269 431 232 0
(sorry for any alignment issues here)
At the moment I only want to look at a single Reader that I specify (through the where clause). Ideally, it would be easier to read if the time sections were in a single column and the results, i.e. a count function were in a second column yielding results such as:
Total Transactions 932
Morning(5am-12pm) 269
AfternoonActivity(12pm-6pm) 431
EveningActivity(6pm-12am) 232
OtherActivity(12am-5am) 0
Thanks for any help :)
I would first consider a computed column, but I believe from a previous post you don't have the ability to change the schema. So how about a view?
CREATE VIEW dbo.GroupedReaderView
AS
SELECT ReaderMACAddress,
Slot = CASE WHEN t >= '05:00' AND t < '12:00' THEN 1
WHEN t >= '12:00' AND t < '18:00' THEN 2
WHEN t >= '18:00' THEN 3 ELSE 4 END
FROM
(
SELECT ReaderMACAddress, t = CONVERT(TIME, [Timestamp])
FROM dbo.Transactions
) AS x;
Now your per-MAC address query is much, much simpler:
SELECT Slot, COUNT(*)
FROM dbo.GroupedReaderView
WHERE ReaderMACAddress = '00...'
GROUP BY Slot;
This will provide a result like:
1 269
2 431
3 232
4 0
You can also add WITH ROLLUP which will provide a grand total with the Slot column being NULL:
SELECT Slot, COUNT(*)
FROM dbo.GroupedReaderView
WHERE ReaderMACAddress = '00...'
GROUP BY Slot
WITH ROLLUP;
Should yield:
1 269
2 431
3 232
4 0
NULL 932
And you can pivot that if you need to, add labels per slot, etc. in your presentation tier.
You could also do it this way, it just makes the view a lot more verbose and pulls a lot of extra data when you query it directly; it's also slightly less efficient to group by strings.
CREATE VIEW dbo.GroupedReaderView
AS
SELECT ReaderMACAddress,
Slot = CASE WHEN t >= '05:00' AND t < '12:00' THEN
'Morning(5am-12pm)'
WHEN t >= '12:00' AND t < '18:00' THEN
'Afternoon(12pm-6pm)'
WHEN t >= '18:00' THEN
'Evening(6pm-12am)'
ELSE
'Other(12am-5am)'
END
FROM
(
SELECT ReaderMACAddress, t = CONVERT(TIME, [Timestamp])
FROM dbo.Transactions
) AS x;
These aren't necessarily more efficient than what you've got, but they're less repetitive and easier on the eyes. :-)
Also if you don't want to (or can't) create a view, you can just put that into a subquery, e.g.
SELECT Slot, COUNT(*)
FROM
(
SELECT ReaderMACAddress,
Slot = CASE WHEN t >= '05:00' AND t < '12:00' THEN
'Morning(5am-12pm)'
WHEN t >= '12:00' AND t < '18:00' THEN
'Afternoon(12pm-6pm)'
WHEN t >= '18:00' THEN
'Evening(6pm-12am)'
ELSE
'Other(12am-5am)'
END
FROM
(
SELECT ReaderMACAddress, t = CONVERT(TIME, [Timestamp])
FROM dbo.Transactions
) AS x
) AS y
WHERE ReaderMACAddress = '00...'
GROUP BY Slot
WITH ROLLUP;
Just an alternative that still lets you use BETWEEN and may be even a little less verbose:
SELECT Slot, COUNT(*)
FROM
(
SELECT ReaderMACAddress,
Slot = CASE WHEN h BETWEEN 5 AND 11 THEN 'Morning(5am-12pm)'
WHEN h BETWEEN 12 AND 17 THEN 'Afternoon(12pm-6pm)'
WHEN h >= 18 THEN 'Evening(6pm-12am)'
ELSE 'Other(12am-5am)'
END
FROM
(
SELECT ReaderMACAddress, h = DATEPART(HOUR, [Timestamp])
FROM dbo.Transactions
) AS x
) AS y
WHERE ReaderMACAddress = '00...'
GROUP BY Slot
WITH ROLLUP;
UPDATE
To always include each slot even if there are no results for that slot:
;WITH slots(s, label, h1, h2) AS
(
SELECT 1, 'Morning(5am-12pm)' , 5, 11
UNION ALL SELECT 2, 'Afternoon(12pm-6pm)' , 12, 17
UNION ALL SELECT 3, 'Evening(6pm-12am)' , 18, 23
UNION ALL SELECT 4, 'Other(12am-5am)' , 0, 4
)
SELECT s.label, c = COALESCE(COUNT(y.ReaderMACAddress), 0)
FROM slots AS s
LEFT OUTER JOIN
(
SELECT ReaderMACAddress, h = DATEPART(HOUR, [Timestamp])
FROM dbo.Transactions
WHERE ReaderMACAddress = '00...'
) AS y
ON y.h BETWEEN s.h1 AND s.h2
GROUP BY s.label
WITH ROLLUP;
The key in all of these cases is to simplify and not repeat yourself. Even if SQL Server only performs it once, why convert to time 4+ times?

SQL statement to get record datetime field value as column of result

I have the following two tables
activity(activity_id, title, description, group_id)
statistic(statistic_id, activity_id, date, user_id, result)
group_id and user_id come from active directory. Result is an integer.
Given a user_id and a date range of 6 days (Mon - Sat) which I've calculated on the business logic side, and the fact that some of the dates in the date range may not have a statistic result for the particular date (ie. day1 and day 4 may have entered statistic rows for a particular activity, but there may not be any entries for days 2, 3, 5 and 6) how can I get a SQL result with the following format? Keep in mind that if a particular activity doesn't have a record for the particular date in the statistics table, then that day should return 0 in the SQL result.
activity_id group_id day1result day2result day3result day4result day5result day6 result
----------- -------- ---------- ---------- ---------- ---------- ---------- -----------
sample1 Secured 0 5 1 0 2 1
sample2 Unsecured 1 0 0 4 3 2
Note: Currently I am planning on handling this in the business logic, but that would require multiple queries (one to create a list of distinct activities for that user for the date range, and one for each activity looping through each date for a result or lack of result, to populate the 2nd dimension of the array with date-related results). That could end up with 50+ queries for each user per date range, which seems like overkill to me.
I got this working for 4 days and I can get it working for all 6 days, but it seems like overkill. Is there a way to simplify this?:
SELECT d1d2.activity_id, ISNULL(d1d2.result1,0) AS day1, ISNULL(d1d2.result2,0) AS day2, ISNULL(d3d4.result3,0) AS day3, ISNULL(d3d4.result4,0) AS day4
FROM
(SELECT ISNULL(d1.activity_id,0) AS activity_id, ISNULL(result1,0) AS result1, ISNULL(result2,0) AS result2
FROM
(SELECT ISNULL(statistic_result,0) AS result1, ISNULL(activity_id,0) AS activity_id
FROM statistic
WHERE user_id='jeremiah' AND statistic_date='11/22/2011'
) d1
FROM JOIN
(SELECT ISNULL(statistic_result,0) AS result2, ISNULL(activity_id,0) AS activity_id
FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/23/2011'
) d2
ON d1.activity_id=d2.activity_id
) d1d2
FULL JOIN
(SELECT d3.activity_id AS activity_id, ISNULL(d3.result3,0) AS result3, ISNULL(d4.result4,0) AS result4
FROM
(SELECT ISNULL(statistic_result,0) AS result3, ISNULL(activity_id,0) AS activity_id
FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/24/2011'
) d3
FULL JOIN
(SELECT ISNULL(statistic_result,0) AS result4, ISNULL(activity_id,0) AS activity_id
FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/25/2011'
) d4
ON d3.activity_id=d4.activity_id
) d3d4
ON d1d2.activity_id=d3d4.activity_id
ORDER BY d1d2.activity_id
Here is a typical approach for this kind of thing:
DECLARE #minDate DATETIME,
#maxdate DATETIME,
#userID VARCHAR(200)
SELECT #minDate = '2011-11-15 00:00:00',
#maxDate = '2011-11-22 23:59:59',
#userID = 'jeremiah'
SELECT A.activity_id, A.group_id,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 0 THEN S.Result ELSE 0 END) AS Day1Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 1 THEN S.Result ELSE 0 END) AS Day2Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 2 THEN S.Result ELSE 0 END) AS Day3Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 3 THEN S.Result ELSE 0 END) AS Day4Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 4 THEN S.Result ELSE 0 END) AS Day5Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 5 THEN S.Result ELSE 0 END) AS Day6Result
FROM activity A
LEFT OUTER JOIN statistic S
ON A.activity_id = S.activity_ID
AND S.user_id = #userID
WHERE S.date between #minDate AND #maxDate
GROUP BY A.activity_id, A.group_id
First, I'm using group by to reduce the resultset to one row per activity_id/group_id, then I'm using CASE to separate values for each individual column. In this case I'm looking at which day in the last seven, but you can use whatever logic there to determine what date. The case statements will return the value of S.result if the row is for that particular day, or 0 if it's not. SUM will add up the individual values (or just the one, if there is only one) and consolidate that into a single row.
You'll also note my date range is based on midnight on the first day in the range and 11:59PM on the last day of the range to ensure all times are included in the range.
Finally, I'm performing a left join so you will always have a 0 in your columns, even if there are no statistics.
I'm not entirely sure how your results are segregated by group in addition to activity (unless group is a higher level construct), but here is the approach I would take:
SELECT activity_id
day1result = SUM(CASE DATEPART(weekday, date) WHEN 1 THEN result ELSE 0 END)
FROM statistic
GROUP BY activity_id
I will leave the rest of the days and addition of group_id to you, but you should see the general approach.

two column two conditions

ID mobileno dateofregistration registrationstate
44 1674174925 2011-04-18 10:17:30.670 0
45 1677864168 2011-03-31 10:20:22.450 1
46 1677864161 2011-04-18 20:47:35.293 0
47 1674174925 2011-03-29 09:28:55.200 1
48 1674174967 2011-03-29 09:28:55.100 1
I've to find how many registrationstate=1 in a given period
how many registrationstate changed from 0 to 1 in the same above given period.
SELECT CONVERT(varchar(10), dateofregistration, 103) AS Date
, COUNT(1) AS Subbase
, SUM(CASE WHEN registrationstate='1' THEN 1 ELSE 0 END) AS NewAct
, SUM(CASE WHEN (registrationstate='0' and registrationstate='1') THEN 1 ELSE 0 END) AS SuccessRen
FROM tbl_User
GROUP BY
CONVERT(varchar(10), dateofregistration, 103)
ORDER BY
1
Creating a calendar table and using that to join help you out for your first query. Define your periods in the calendar table and then it is a simple matter of some joins and a count statement grouping by your calendar table period.
The second query would be similar, but I would make a subquery of mobilenumbers = 0 and join all the 1's to that subquery for the timeperiod.
During my coding of the solution, I'm sure I'd discover I was mistaken about a few of these approaches ;)