Access database query for using month from a date - sql

I have the following table schema in acess (2007).
Date eventDate bit(boolean) lunch,
bit(boolean) snacks, bit(boolean) Tea,
I would like to have a single query that gives count of luch, snacks and tea (each as a column) for a given month (using the eventdate).
Thanks for help.

In Access, True is -1 and False is 0. So you can use the absolute value of the sum of those values to indicate how many were True.
SELECT Abs(Sum(lunch)) AS SumofLunch, Abs(Sum(snacks)) AS SumofSnacks, Abs(Sum(Tea)) AS SumofTea
FROM YourTable
WHERE eventDate >= #2009/08/01# And eventDate < #2009/09/01#;

Try:
SELECT SUM(ABS(lunch)) AS lunchCount, SUM(ABS(snacks)) AS snackCount, SUM(ABS(tea)) AS teaCount
FROM <TableName>
WHERE eventDate >= #1/1/2009# AND eventDate < #2/1/2009#

I'd attack this in access using IIF statements (think like CASE statements in other databases). IIF in Access returns a value when the specified condition is true (after the first comma) or another value if it evaluates to false (after the second comma). Because you are using booleans, checking for a true condition and rolling up via an aggregate sum will do the trick for you.
SELECT Month(EventDate) AS TheMonth, Year(EventDate) AS TheYear,
SUM(IIF(Lunch, 1, 0)) AS LunchCount,
SUM(IIF(Snacks, 1, 0)) AS SnackCount,
SUM(IIF(Tea, 1, 0)) AS TeaCount
FROM YourTable
GROUP BY Month(EventDate), Year(EventDate)
ORDER BY Month(EventDate), Year(EventDate)
The above query of course returns counts for all months and years however you could easily key in on a date range like below if need be.
SELECT Month(EventDate) AS TheMonth, Year(EventDate) AS TheYear,
SUM(IIF(Lunch, 1, 0)) AS LunchCount,
SUM(IIF(Snacks, 1, 0)) AS SnackCount,
SUM(IIF(Tea, 1, 0)) AS TeaCount
FROM YourTable
WHERE EventDate BETWEEN #1/1/2009# AND #1/31/2009#
GROUP BY Month(EventDate), Year(EventDate)
ORDER BY Month(EventDate), Year(EventDate)

Related

SQL with as expression shows multiple results

I am writing a SQL query using with as expression. I always get a result in the square of what I required.
This is my query:
DECLARE #MAX_DATE AS INT
SET #MAX_DATE = (SELECT DATEPART(MONTH,FECHA) FROM ALBVENTACAB WHERE NUMALBARAN IN (SELECT DISTINCT MAX(NUMALBARAN) FROM ALBVENTACAB));
;WITH TABLE_LAST AS (
SELECT CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA)) as LAST_YEAR_MONTH
,SUM(TOTALNETO) AS LAST_YEAR_VALUE
FROM ALBVENTACAB
WHERE DATEPART(YEAR,CURRENT_TIMESTAMP) -1 = DATEPART(YEAR,FECHA) AND NUMSERIE LIKE 'A%'
AND DATEPART(MONTH,FECHA) <= #MAX_DATE
GROUP BY CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA))
)
,TABLE_CURRENT AS(
SELECT CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA)) as CURR_YEAR_MONTH
,SUM(TOTALNETO) AS CURR_YEAR_VALUE
FROM ALBVENTACAB
WHERE DATEPART(YEAR,CURRENT_TIMESTAMP) <= DATEPART(YEAR,FECHA) AND NUMSERIE LIKE 'A%'
GROUP BY CONCAT(DATEPART(MONTH,FECHA),'-',DATEPART(YEAR,FECHA))
)
SELECT *
FROM TABLE_CURRENT, TABLE_LAST
When I run the query I get exactly the square of the result.
I want to compare sale monthly with last year.
2-2020 814053.3 2-2019 840295.1
1-2020 1094993.65 2-2019 840295.1
3-2020 293927.3 2-2019 840295.1
2-2020 814053.3 1-2019 1050701.68
1-2020 1094993.65 1-2019 1050701.68
3-2020 293927.3 1-2019 1050701.68
2-2020 814053.3 3-2019 887776.1
1-2020 1094993.65 3-2019 887776.1
3-2020 293927.3 3-2019 887776.1
I should get only 3 rows instead of 9 rows.
You need to properly join your two CTE - the way you're doing it now, you're getting a Cartesian product of each row in either CTE together.
Do something like:
*;WITH TABLE_LAST AS
( ....
),
TABLE_CURRENT AS
( ....
)
SELECT *
FROM TABLE_CURRENT curr
INNER JOIN TABLE_LAST last ON (some join condition here)
What that join condition is going to be - I have no idea, and cannot tell from your question - but you have to define how these two sets of data "connect" ....
It could be something like:
SELECT *
FROM TABLE_CURRENT curr
INNER JOIN TABLE_LAST last ON curr.CURR_YEAR_MONTH = last.LAST_YEAR_MONT
or whatever else makes sense in your situation - but basically, you need to somehow "tie together" these two sets of data and get only those rows that make sense - not just every row from "last" combined with every row from "curr" ....
While you already got the answer on how to join the two results, I thought I'd tell you how to typically approach such problems.
From the same table, you want two sums on different conditions (different years that is). You solve this with conditional aggregation, which does just that: aggregate (sum) based on a condition (year).
select
datepart(month, fecha) as month,
sum(case when datepart(year, fecha) = datepart(year, getdate()) then totalneto end) as this_year,
sum(case when datepart(year, fecha) = datepart(year, getdate()) -1 then totalneto end) as last_year
from albventacab
where numserie like 'A%'
and fecha > dateadd(year, -2, getdate())
group by datepart(month, fecha)
order by datepart(month, fecha);

SQL Query - how to create a sum based on grouped numbers

I'd like to know how many messages (voicemailcount) were received for each rank (b.rankcode). Example Column 'b.rankcode' will have x number of people with a rank number who have gotten messages in 'voicemailcount'. If possible, I'd only like to see the voicemailcount and rankcode column.
select
count(*) as [voicemailcount], a.linkedusermailboxname, b.RankCode as 'Rank'
from
UMCallDataRecord a
join
UMADUserAccounts b on a.LinkedUserMailboxName = b.EmailAddress
where
a.CallType = 'callansweringvoicemessage'
and month(a.[date]) = month(GetDate()) - 1 -- change this per month -1 = lastmonth
group by
a.linkedusermailboxname, b.rankcode
order by
b.rankcode
TIA!
I believe that we need to remove "linkedusermailboxname" from the Select and from the GroupBy, and remove the Join table and its On... >>
SELECT
b.rankcode AS 'Rank'
,Count(*) AS [voicemailcount]
FROM umcalldatarecord a
WHERE a.calltype = 'callansweringvoicemessage'
AND Month(a.[date]) = Month(Getdate()) - 1
-- change this per month -1 = lastmonth
GROUP BY b.rankcode
ORDER BY b.rankcode
Seems like you just need to reduce the number of columns that you group by
SELECT
COUNT(*) AS [voicemailcount]
, ua.RankCode AS 'Rank'
FROM UMCallDataRecord AS cdr
JOIN UMADUserAccounts AS ua ON cdr.LinkedUserMailboxName = ua.EmailAddress
WHERE cdr.CallType = 'callansweringvoicemessage'
AND cdr.[date] >= dateadd(month, datediff(month,0, getDate())-1, 0) -- 1st day of last month
AND cdr.[date] < dateadd(month, datediff(month,0, getDate()), 0) -- 1st day of current month
GROUP BY
ua.rankcode
ORDER BY
ua.rankcode
However I would like to propose a different way to define the date range because you could include results from any year in your current approach. The approach above will limit the results to everything from the previous month, and only the previous month. Note also I do not use between which just isn't great for date ranges.
I also concur with "Bad habits to kick : using table aliases like (a, b, c) or (t1, t2, t3)", use meaningful aliases, not aliases based on "sequence in a query"

is there a way to use an if statement in the WHERE part of the SQL query?

Is there a way to use an if statement in the where part of the SQL query? For example:
SELECT count(*)
from table_name tb
where ( if (#enddate>dateadd("d",2,#date) then date > tb.date
else dateadd("d",2,#date)>tb.date) )
I need to somehow do this check where I check if the date 2 days later is not greater than the end date, otherwise I have to use the end date by default.
You can use CASE expression:
SELECT count(*)
FROM table_name tb
WHERE (CASE WHEN (#enddate>dateadd("d",2,#date)) THEN date > tb.date
ELSE
dateadd("d",2,#date)>tb.date
END);
this answer is tailored onto to the case explained into the question as the issue to solve and not on the title.
to handle that case there is no need for a special solution and/or keyword, it is handled nicely using a regular WHERE clause:
SELECT count(*)
from table_name tb
where (#enddate > dateadd("d",2,#date) AND date > tb.date)
OR
(dateadd("d",2,#date) > tb.date))
I found the following:
CASE
WHEN (DATENAME(dw,#st) = 'Monday')
AND (
((Day(#st) = 01))
OR ((Day(#st) = 02))
OR ((Day(#st) = 03))
)
THEN DATEADD(DAY,-2,#st)
ELSE DATEADD(DAY, - 1, DATEADD(m, DATEDIFF(m, 0, GETDATE()), 0))
END
And it actually works quite nicely.
This will only run when the first working day of the month is a Monday, hence that's when I want to get the weekend's data. Otherwise, I already have it.

ORDER BY, set a specific case to the first index?

Using SQL Server 2008...
I'm having some troubles in trying to order my rows in a specific order that I would like them to be ordered by. I've found a few examples that use the ORDER BY CASE clause, but am unsure whether using this method will produce the result that I want it to, thus I come to the community!
Here's what I have:
First, I select, if it exists, a distinct year that is equal to the current year:
IF EXISTS(SELECT DISTINCT [Year]
FROM Assessment WHERE ProjectCode = #ProjectCode AND [Year] = DATENAME(YEAR, GETDATE()))
SELECT DISTINCT [Year]
FROM Assessment WHERE ProjectCode = #ProjectCode
But, then I find some confusion in ordering the results. I'd like to set the current year to the first row returned using the ORDER BY clause, then order the rest of the returned years in a descending order, here's what I have so far:
ORDER BY (CASE WHEN [Year] = (DATENAME(YEAR, GETDATE())) THEN 1
ELSE 100 END) ASC, [Year] desc
Next, if the current year is not contained in the query, select each year and order by year descending.
ELSE
SELECT DISTINCT [Year]
FROM Assessment WHERE ProjectCode = #ProjectCode
ORDER BY [Year] desc
Thanks, in advance!
You don't need conditional statements here at all:
SELECT *
FROM (
SELECT DISTINCT [Year]
FROM Assessment
WHERE projectCode = #projectCode
) q
ORDER BY
CASE [Year] WHEN YEAR(GETDATE()) THEN 1 ELSE 2 END,
[Year]
will output the current year (if exists) first, the other later.
You're question isn't very clear because you don't specify what is broken or where you're having issues. From what I gather, however, you don't need an IF/ELSE. Instead you could do something like ...
SELECT DISTINCT [Year],
CASE [Year]
WHEN DATENAME(Year, GETDATE()) THEN 9999
ELSE [Year] END AS GarbageSoDistinctWorks
FROM Assessment
WHERE ProjectCode = #ProjectCode
ORDER BY
CASE [Year]
WHEN DATENAME(Year, GETDATE()) THEN 9999
ELSE [Year] END DESC
FYI ... i added the case to the select list as a throw away column to avoid the error I assume you're getting.. There are other ways, like a derived table, but for now this should work..
Msg 145, Level 15, State 1, Line 2
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
HTH,
-eric
Your example code appears to do what you describe. What problems are you having?
As a side note: You don't need the IF statement. By using the ORDER BY from your first example (with the CASE statement), you will get the correct results for both scenarios.
- If "this year" is in your data, it comes first. Everything else comes next in DESC order
- If "this year" isn't in your data, you just get everything else in DESC order

Using sub-query to count specific rows

I have a query that I am using for a report. Each line is a row of data containing a medical history, the client_id is repeated for each medical history.
I'm grouping by client_id and summing their conditions but I want to use a sub-query to find any conditions that are above a preset score. My current query is giving me the total for the whole table, not just the specific client_id.
Can someone help me out? Thanks!
Here my query:
select
DATEADD(month, DATEDIFF(month, 0, taken_on), 0),
client_id,
count(hscore),
sum(hscore),
(select count(hscore)
from amexmedscreen
where hscore >= '3.5')
from amexmedscreen
group by taken_on, client_id`
It should be sufficient to use CASE to get 1 for relevant rows, and sum those:
select
...
sum(hscore),
sum(CASE WHEN hscore >= 3.5 THEN 1 ELSE 0 END)
group by taken_on, client_id`
Your subquery is a separate query. It's not constrained by what's going on in the main query. You need to tell it to do the count only for the client_id of the current record in the outer query. You'll be referring to the same table twice in two different queries, so you'll have to use a different alias for each one.
Something like this should work:
select DATEADD(month, DATEDIFF(month, 0, taken_on), 0),
client_id,
count(hscore),
sum(hscore),
(select count(hscore)
from amexmedscreen subq
where
hscore >= '3.5'
and subq.client_id = outerq.client_id )
from amexmedscreen outerq
group by taken_on, client_id
select DATEADD(month, DATEDIFF(month, 0, taken_on), 0),
client_id,
count(hscore),
sum(hscore),
tb1.COUNT_HSCORE
from amexmedscreen
INNER JOIN
(select client_id, count(hscore) as COUNT_HSCORE
from amexmedscreen
where hscore >= '3.5'
group by client_ID) as tb1
ON tb1.client_id = client id
group by taken_on, client_id,tb1.COUNT_HSCORE