So essentially I have a table that looks like this:
SalesPerson Target
John 50000.00
Bill 75000.00
Jake 40000.00
I want to add a new column that will make my query look like this:
SalesPerson Target Month
John 50000.00 01/01/14
Bill 75000.00 01/01/14
Jake 40000.00 01/01/14
John 50000.00 02/01/14
Bill 75000.00 02/01/14
Jake 40000.00 02/01/14
And so on.... Obviously the target is a monthly value. The purpose is to be used in a pivot chart in Tableau.
The month field needs to be datetime which should be easy. The only thing coming to mind is to manually do something like:
Convert(datetime, '2014-01-01 00:00:000') as 'MONTH'
and then do that 11 more times and use UNION all each time. This just seems like a lot of text and time. I'm hoping there is a much easier way.
Thanks in advance for all the help!
This is a somehow bizarre scenario, why would you need to repeat every value of your table for every month?. That said, this is one way to do it:
SELECT A.*,
DATEADD(MONTH,B.number,'20140101') AS [Month]
FROM YourTable A
CROSS JOIN (SELECT *
FROM master.dbo.spt_values
WHERE type = 'P'
AND number BETWEEN 0 AND 11) B
Do be aware that this is multiplying the number of rows of your table by 12.
Related
I have a simple query to which I forgot the solution, I remember there was a function to look for each possible value in a range, so I am asking this query here.
There is a table 'Time' with 2 columns checkInTime and CheckOutTime of the employees for one day in the office.
in the format: hour*100+minutes
For instance:
Check in
Check out
850
1758
902
1640
1330
1530
1630
2020
Find out the number of people which were in office at 6 pm (1800)
To this I came with this query (obviously its wrong since I dont know how to look for the value 1800 in the checkin-checkout range):
select sum(rn)
from Table
row_number() over() as rn
Where Checkout >= 1800
SELECT COUNT(*)
FROM table
WHERE 1800 BETWEEN CheckIn AND CheckOut)
That said this is incomplete without a full date to qualify that they were not in longer than a day.
Thanks in advance.
I have Customer records that look like this:
Customer_Number
Create_Date
34343
01/22/2001
54554
03/03/2020
85296
01/01/2001
...
I have about a thousand of these records (customer number is unique) and the bossman wants to see how the number of customers has grown over time.
The output I need:
Customer_Count
Monthly_Bucket
7
01/01/2021
9
02/01/2021
13
03/01/2021
20
04/01/2021
The customer count is cumulative and the Monthly Bucket will just feed the graphing package to make a nice bar chart answering the question "how many customers to we have in total in a particular month and how is it growing over time".
Try the following SELECT SQL with a sub-query:
SELECT Customer_Count=
(
SELECT COUNT(s.[Create_Date])
FROM [Customer_Sales] s
WHERE MONTH(s.[Create_Date]) <= MONTH(t.[Create_Date])
), Monthly_Bucket=MONTH([Create_Date])
FROM Customer_Sales t
WHERE YEAR(t.[Create_Date]) = ????
GROUP BY MONTH(t.[Create_Date])
Where [Customer_Sales] is the sales table and ??? = your year
In MS ACCESS, I have a table containing names and dates for when a persons yearly exam expires. This exam is valid for 12 months, so the next exam is typically done before all 12 months have expired.
Table, called "Exam", looks like this (in the real table names are unique):
ID Name Dateexp
1 Peter 30/07/2020
2 john 10/09/2020
3 Bob 11/10/2019
4 Peter 25/06/2021
I have a query that shows the persons with a "valid" exam. I looks like this:
SELECT Name As Name, Dateexp As Expiry FROM Overall WHERE Dateexp > now();
It returns:
Name Expiry
Peter 30/07/2020
John 10/09/2020
Peter 25/06/2021
Problem is that "Peter" has done a new exam thereby extending his expiry date from 30/07/2020 to 25/06/21 and I only want the latest one to be shown.
Query should return:
Name Expiry
Peter 25/06/2021
John 10/09/2020
I am truly lost - does anyone have an idea as to how this can be solved?
Thank you!
You can use max and having clause:
Select name, max(dateexp) as dateexp
from overall
Group by name
Having max(dateexp) > now()
If I followed you correctly, you can just use aggregation, and filter with a having clause:
select name, max(dateexp) as expiry
from overall
group by name
having max(dateexp) > now();
This filters on names whose latest expiry date is in the future.
The problem I'm facing is probably easy to fix, but I can't seem to find an answer online due to the specificity of the issue.
In my database, I have a 3 tables to denote how an educational course is planned. Suppose there is a course called Working with Excel. This means the table Courses has a row for this.
The second table denotes cycles of the same course. If the course is given on Jan 1 2013 and Feb 1 2013, in the underlying tables Cycles, you will find 2 rows, one for each date.
I currently already have an SQL script that gives me two columns: The course name, and a comma separated list with all the Cycle dates.
Please note I am using dd/MM/yyyy notation
This is how it's currently set up (small excerpt, this is the SELECT statement to explain the desired output):
SELECT course.name,
stuff((SELECT distinct ',' + CONVERT(varchar(10), cycleDate, 103) --code 101 = mm/dd/yyyy, code 103 = dd/mm/yyyy
FROM cycles t2
where t2.courseID= course.ID and t2.cycleDate > GETDATE()
FOR XML PATH('')),1,1,'') as 'datums'
The output it gives me:
NAME DATUMS
---------------------------------------------------
Working with Excel 01/01/2013,01/02/2013
Some other course 12/3/2013, 1/4/2013, 1/6/2013
The problem is that I need to add info from the third table I haven't mentioned yet. The table ExtraDays contains additional days for a cycle, in case this spans more than a day.
E.g., if the Working with Excel course takes 3 days, (Jan 1+2+3 and Feb 1+2+3), each of the course cycles will have 2 ExtraDays rows that contain the 'extra days'.
The tables would look like this:
Table COURSES
ID NAME
---------------------------------------------------
1 Working with Excel
Table CYCLES
ID DATE COURSEID
---------------------------------------------------
1 1/1/2013 1
2 1/2/2013 1
Table EXTRADAYS
ID EXTRADATE CYCLEID
---------------------------------------------------
1 2/1/2013 1
2 3/1/2013 1
3 2/2/2013 2
4 3/2/2013 2
I need to add these ExtraDates to the comma-separated list of dates in my output. Preferably sorted, but this is not necessary.
I've been stumped quite some time by this. I have some SQL experience, but apparently not enough for this issue :)
I'm hoping to get the following output:
NAME DATUMS
--------------------------------------------------------------------------------------
Working with Excel 01/01/2013,02/01/2013,03/01,2013,01/02/2013,02/02/2013,03/02/2013
I'm well aware that the database structure could be improved to simplify this, but unfortunately this is a legacy application, I cannot change the structure.
Can anyone point me in the right way to combining these two columns.
I hope I described my issue clear enough for you. Else, just ask :)
SELECT course.name,
stuff((SELECT distinct ',' + CONVERT(varchar(10), cycleDate, 103) --code 101 = mm/dd/yyyy, code 103 = dd/mm/yyyy
FROM (select id, date, courseid from cycles
union
select id, extradate, courseid from extradays) t2
where t2.courseID= course.ID and t2.cycleDate > GETDATE()
FOR XML PATH('')),1,1,'') as 'datums'
If I have a table containing schedule information that implies particular dates, is there a SQL statement that can be written to convert that information into actual rows, using some sort of CROSS JOIN, perhaps?
Consider a payment schedule table with these columns:
StartDate - the date the schedule begins (1st payment is due on this date)
Term - the length in months of the schedule
Frequency - the number of months between recurrences
PaymentAmt - the payment amount :-)
SchedID StartDate Term Frequency PaymentAmt
-------------------------------------------------
1 05-Jan-2003 48 12 1000.00
2 20-Dec-2008 42 6 25.00
Is there a single SQL statement to allow me to go from the above to the following?
Running
SchedID Payment Due Expected
Num Date Total
--------------------------------------
1 1 05-Jan-2003 1000.00
1 2 05-Jan-2004 2000.00
1 3 05-Jan-2005 3000.00
1 4 05-Jan-2006 4000.00
1 5 05-Jan-2007 5000.00
2 1 20-Dec-2008 25.00
2 2 20-Jun-2009 50.00
2 3 20-Dec-2009 75.00
2 4 20-Jun-2010 100.00
2 5 20-Dec-2010 125.00
2 6 20-Jun-2011 150.00
2 7 20-Dec-2011 175.00
I'm using MS SQL Server 2005 (no hope for an upgrade soon) and I can already do this using a table variable and while loop, but it seemed like some sort of CROSS JOIN would apply but I don't know how that might work.
Your thoughts are appreciated.
EDIT: I'm actually using SQL Server 2005 though I initially said 2000. We aren't quite as backwards as I thought. Sorry.
I cannot test the code right now, so take it with a pinch of salt, but I think that something looking more or less like the following should answer the question:
with q(SchedId, PaymentNum, DueDate, RunningExpectedTotal) as
(select SchedId,
1 as PaymentNum,
StartDate as DueDate,
PaymentAmt as RunningExpectedTotal
from PaymentScheduleTable
union all
select q.SchedId,
1 + q.PaymentNum as PaymentNum,
DATEADD(month, s.Frequency, q.DueDate) as DueDate,
q.RunningExpectedTotal + s.PaymentAmt as RunningExpectedTotal
from q
inner join PaymentScheduleTable s
on s.SchedId = q.SchedId
where q.PaymentNum <= s.Term / s.Frequency)
select *
from q
order by SchedId, PaymentNum
Try using a table of integers (or better this: http://www.sql-server-helper.com/functions/integer-table.aspx) and a little date math, e..g. start + int * freq
I've used table-valued functions to achieve a similar result. Basically the same as using a table variable I know, but I remember being really pleased with the design.
The usage ends up reading very well, in my opinion:
/* assumes #startdate and #enddate schedule limits */
SELECT
p.paymentid,
ps.paymentnum,
ps.duedate,
ps.ret
FROM
payment p,
dbo.FUNC_get_payment_schedule(p.paymentid, #startdate, #enddate) ps
ORDER BY p.paymentid, ps.paymentnum
A typical solution is to use a Calendar table. You can expand it to fit your own needs, but it would look something like:
CREATE TABLE Calendar
(
calendar_date DATETIME NOT NULL,
is_holiday BIT NOT NULL DEFAULT(0),
CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED calendar_date
)
In addition to the is_holiday you can add other columns that are relevant for you. You can write a script to populate the table up through the next 10 or 100 or 1000 years and you should be all set. It makes queries like that one that you're trying to do much simpler and can give you additional functionality.