using datepart() with the group by command - sql

I am beating my head against something that is, I'm sure, very obvious -
I have a bit of SQL code designed to sum the total selling price of each invoice in my store and then organize it by Month.
select SUM(totalsellingprice) from dbo.tblServiceOrders
where datepart(MONTH,dbo.tblServiceOrders.datereceived) =12
As far as I understand it, that should return the sum of all the totatlsellingprice from month 12 (December). Currently, this query returns
135998.92
However, if I then try to put that into a group by to get it to spit it out for all months, the number changes.
select SUM(totalsellingprice) from dbo.tblServiceOrders
group by datepart(MONTH,dbo.tblServiceOrders.datereceived)
And I get this table -
1 - 110567.70
2 - 60059.59
3 - 135998.92
4 - 63089.22
5 - 102287.01
6 - 71088.68
7 - 149102.10
8 - 67722.65
9 - 67122.45
10 - 64234.82
11 - 7542.05
12 - 130461.10
There are 12 rows, which sounds good to me (12 months in a year) but the last row is 130461.
How is it possible that row 12 from the second search does not equal what I did in the first search? I feel like I'm missing something obvious but I can't for the life of me figure out what.
Any and all help will be much appreciated!

I got it:
Your query is very confusing since it does not include the MONTH column:
If you would have done that, you would have realized your query is not ordered by MONTH and so, the MONTH 12 is returned as the 3rd row of your query.
;)
select SUM(totalsellingprice) from dbo.tblServiceOrders
group by datepart(MONTH,dbo.tblServiceOrders.datereceived)
order by datepart(MONTH,dbo.tblServiceOrders.datereceived)
And please, don't refer to the row index to choose which month is related to which sum. And should be a good idea to also discriminate the year (if you need to).

Run this and see what it does...
select dateadd(month, datediff(month, 0, datereceived), 0),
Sum(totalsellingprice)
from dbo.tblServiceOrders
group by dateadd(month, datediff(month, 0, datereceived), 0)

Related

Group data from 3 tables and sort by week ending date

Here is the problem I am stuck on.
I have three tables which log the dates and locations customers visit my sales centers. One table is the initial visit, the second is a able for repeat visits, of which there could be many and the third is a deposit table which stores the data related to when people leave a deposit and on which job they left the deposit.
So I need to sort all do this data by the week ending date, which I do have working on one table at a time. So for example, anyone who visited my sales center on March 3 would be counted in as traffic for the week ending march 9.
Now I would like to query the data so that I call pull the dates from the other two tables as well and have them sort by week ending along with the other data.
So my final output would look like this:
Week ending | initial visit | bback | deposit
3/9/2014 9 3 0
3/16/2104. 12. 0. 1
My tables structure looks like this:
Salescenter_clientinfo
Initial_visit (date)
Community
Customer_bback
Bback_date
Bback_community
Customer Deposit
Deposit_date
Doposit_community
All of these tables also have a field which is the customer_id which links them all.
As stated earlier, I do have the sql working which gets the job done using one table but how do I accomplish this on multiple tables?
I forgot to mention, I run this sql from an excel pivot table against an MSSql database. I am using excel to do the pivot and be the final report.
Any help in very much appreciated.
Thanks in advance.
Steve
If I'm understanding your original question correctly, you're trying to track everything that happened at your center, in each category, during a specific week. So if a customer's initial visit was during week 1, and he/she came back during week 2, those two items would fall under different weeks.
Based on that assumption, the linkage on Customer_ID is actually a bit of a red herring: you want data aggregated by week, and don't care if it all reflects the same customer's initial visit.
If so, then the following SQL might do what you are looking for:
Set Datefirst 1;
SELECT
ISNULL(vc.WeekEnding, ISNULL(b.WeekEnding, d.WeekEnding)) WeekEnding,
vc.InitialVisit,
b.BBack,
d.Deposit
FROM
(
SELECT
DATEADD(dd, 7 - DATEPART(DW, initial_visit), initial_visit) AS WeekEnding,
COUNT(initial_visit) AS InitialVisit
FROM dbo.SalesCenter_clientinfo
GROUP BY DATEADD(dd, 7 - DATEPART(DW, initial_visit), initial_visit)
) vc
FULL OUTER JOIN
(
SELECT
DATEADD(dd, 7 - DATEPART(DW, Bback_date), Bback_date) AS WeekEnding,
COUNT(Bback_date) AS BBack
FROM dbo.Customer_bback
GROUP BY DATEADD(dd, 7 - DATEPART(DW, Bback_date), Bback_date)
) b ON
vc.WeekEnding = b.WeekEnding
FULL OUTER JOIN
(
SELECT
DATEADD(dd, 7 - DATEPART(DW, Deposit_date), Deposit_date) AS WeekEnding,
COUNT(Deposit_date) AS Deposit
FROM dbo.Customer_deposit
GROUP BY DATEADD(dd, 7 - DATEPART(DW, Deposit_date), Deposit_date)
) d ON
vc.WeekEnding = d.WeekEnding
Fiddle

Using iif to mimic CASE for days of week

I've hit a little snag with one of my queries. I'm throwing together a simple chart to plot a number of reports being submitted by day of week.
My query to start was :
SELECT Weekday(incidentdate) AS dayOfWeek
, Count(*) AS NumberOfIncidents
FROM Incident
GROUP BY Weekday(incidentdate);
This works fine and returns what I want, something like
1 200
2 323
3 32
4 322
5 272
6 282
7 190
The problem is, I want the number returned by the weekday function to read the corresponding day of week, like case when 1 then 'sunday' and so forth. Since Access doesn;t have the SQL server equivalent that returns it as the word for the weekday, I have to work around.
Problem is, it's not coming out the way I want. So I wrote it using iif since I can't use CASE. The problem is, since each iif statement is treated like a column selection (the way I'm writing it), my data comes out unusable, like this
SELECT
iif(weekday(incidentdate) =1,'Sunday'),
iif(weekday(incidentdate) =2,'Monday')
'so forth
, Count(*) AS NumberOfIncidents
FROM tblIncident
GROUP BY Weekday(incidentdate);
Expr1000 Expr1001 count
Sunday 20
Monday 106
120
186
182
164
24
Of course, I want my weekdays to be in the same column as the original query. Halp pls
Use the WeekdayName() function.
SELECT
WeekdayName(Weekday(incidentdate)) AS dayOfWeek,
Count(*) AS NumberOfIncidents
FROM Incident
GROUP BY WeekdayName(Weekday(incidentdate));
As BWS Suggested, Switch was what I wanted. Here's what I ended up writing
SELECT
switch(
Weekday(incidentdate) = 1, 'Sunday',
Weekday(incidentdate) = 2,'Monday',
Weekday(incidentdate) = 3,'Tuesday',
Weekday(incidentdate) = 4,'Wednesday',
Weekday(incidentdate) = 5,'Thursday',
Weekday(incidentdate) = 6,'Friday',
Weekday(incidentdate) = 7,'Saturday'
) as DayOfWeek
, Count(*) AS NumberOfIncidents
FROM tblIncident
GROUP BY Weekday(incidentdate);
Posting this here so there's actual code for future readers
Edit: WeekdayName(weekday(yourdate)) as HansUp said it probably a little easier :)
check this previous post:
What is the equivalent of Select Case in Access SQL?
Why not just create a 7 row table with day number & day name then just join to it?

To display only previous three months even the months before is not exist in database

Below is my new sql so far as i do not manage to use Dale M advice,
SELECT
all_months.a_month_id AS month,
year($P{date}) as year,
count(case when clixsteraccount.rem_joindate between DATE_FORMAT($P{date}-INTERVAL 2 MONTH, '%Y-%m-01') AND $P{date} THEN clixsteraccount.rem_registerbycn end) AS
total_activation,
'ACTIVATION(No)' AS fake_column
FROM clixsteraccount right join all_months on all_months.a_month_id = date_format(clixsteraccount.rem_joindate,'%m') and
(clixsteraccount.rem_registrationtype = 'Normal')and(clixsteraccount.rem_kapowstatus='pending' or clixsteraccount.rem_kapowstatus='success')
GROUP BY year,month
HAVING month BETWEEN month(date_sub($P{date},interval 2 month)) and month($P{date})
So, what i do is create a table with two fields, a_month_id(1,2,3...,12) and a_month(name of months). Sql above does give me what i want which is to display previous 3 months even the months before is not exist.
exp: data start on July. So, i want to display May,June and July data like 0,0,100.
The problem occur when it comes to next months or next year. When i try to generate sql based on parameter on Jan, it doesn't work like i thought. I do realize the problem are with 'Having' condition. Do anyone have idea how to improvised this sql to make it continue generate in the next,next year.
Thank you in advanced.
OK, I will make a few suggestions and give you an answer that will work on SQL Server - you will need to make any translations yourself.
I note that your query will aggregate all years together, i.e. Dec 2012 + Dec 2013 + Dec 2014 etc. Based on your question I don't think that is your intention so I will keep each distinct. You can change the query if that was your intention. I have also not included your selection criteria (other than by the month).
I suggest that you utilize an index table. This is a table stored in your database (or the master database if possible) with an clustered indexed integer column running from 0 to n where n is a sufficiently large number - 10,000 will be more than enough for this application (there are 12 months in a year so 10,000 represents 833 years). This table is so useful everyone should have one.
SELECT DATEADD(month, it.id, 0 ) AS month
,ISNULL(COUNT(clixsteraccount.rem_registerbycn), 0) AS registration
,'REGISTRATION(No)' AS fake_column
FROM cn
INNER JOIN ON ca.rem_registerbycn = cn.cn_id
clixsteraccount ca
RIGHT JOIN
IndexTable it ON it.id = DATEDIFF(month, 0, clixsteraccount.rem_joindate)
WHERE it.id BETWEEN DATEDIFF(month, 0, #StartDate) - 3 AND DATEDIFF(month, 0, GETDATE())
GROUP BY it.id
The way it works is by converting the clixsteraccount.rem_joindate to an integer that represents the number of months since date 0 (01-01-1900 in SQL Server). This is then matched to the id column of the IndexTable and limited by the dates you select. Because every number exists in the index table and we are using an outer join it doesn't matter if there are months missing from your data.

SQL query with week days

I would like to know what is the best way of creating a report that will be grouped by the last 7 days - but not every day i have data. for example:
08/01/10 | 0
08/02/10 | 5
08/03/10 | 6
08/04/10 | 10
08/05/10 | 0
08/06/10 | 11
08/07/10 | 1
is the only option is to create a dummy table with those days and join them altogether?
thank you
Try something like this
WITH LastDays (calc_date)
AS
(SELECT DATEADD(DAY, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP) - 6, 0)
UNION ALL
SELECT DATEADD(DAY, 1, calc_date)
FROM LastDays
WHERE DATEADD(DAY, 1, calc_date) < CURRENT_TIMESTAMP)
SELECT ...
FROM LastDays l LEFT JOIN (YourQuery) t ON (l.cal_date = t.YourDateColumn);
Many people will suggest methods for dynamically creating a range of dates that you can then join against. This will certainly work but in my experience a calendar table is the way to go. This will make the SQL trivial and generic at the cost of maintaining the calendar table.
At some point in the future someone will come along and ask for another report that excludes weekends. You then have to make your dynamic days generation account for weekends. Then someone will ask for working-days excluding public-holidays at which point you have no choice but to create a calendar table.
I would suggest you bite the bullet and create a calendar table to join against. Pre-populate it with every date and if you want to think ahead then add columns for "Working Day" and maybe even week number if your company uses a non-standard week-number for reporting
You don't mention the specific language (please do for a more detailed answer), but most versions of sql have a function for the current date (GetDate(), for instance). You could take that date, subtract x (7) days and build your WHERE statement like that.
Then you could GROUP BY the day-part of that date.
select the last 7 transactions and left join it with your query and then group by the date column. hope this helps.

Selecting products that haven't been made in 2 years

I'm trying to get the products that havn't been made in the last 2 years. I'm not that great with SQL but here's what i've started with and it doesn't work.
Lets say for this example that my schema looks like this
prod_id, date_created, num_units_created.
I'll take any advice i can get.
select id, (select date from table
where date <= sysdate - 740) older,
(select date from table
where date >= sysdate - 740) newer
from table
where newer - older
I'm not being clear enough.
Basically i want all products that havn't been produced in the last 2 years. Whenever a product is produced, a line gets added. So if i just did sysdate <= 740, it would only give me all the products that were produced from the beginning up til 2 years ago.
I want all products that have been produced in the at least once, but not in the last 2 years.
I hope that clears it up.
GROUP BY with HAVING
select id, max(date)
from table
group by id
having max(date) < add_months(sysdate,-24)
I'd use SQL's dateadd function.
where date < dateadd(year,-2,getdate())
would be a where clause that would select records with date less than 2 years from the current date.
Hope that helps.
EDIT: If you want to go by days, use dateadd(d,-740,getdate())
Maybe something like this?
select id, date
from table
where date <= (sysdate - 730);
SELECT id FROM table WHERE date + (365*2) <= sysdate;
Use SELECT id, date, other, columns ... if you need to get them at the same time.