I have a table that has a bunch of companies listed in it. I need to make a dictionary view that combines some of the company data, and in addition, every month of the past 3 years up to the current month.
So for example I would pull the cmp_num, then have additional columns for year and month. It's important that the actual years not be hard coded, since I would want this to continue to work in the following years.
cmp1, 2014, 11
cmp1, 2014, 10
cmp1, 2014, 09
...etc for all months of 2014
cmp1, 2013, 01
...etc for all months of 2013
cmp1, 2014
...etc for all months of 2012
*and so on for all companies
Do I need a seed table with the years and months listed? Or is there a way to create this on the fly with a calculating view? Which approach would be better in tsql?
Here's a List of the stuff I need to join with the year\month list.
[cmp_code]
[Name]
[City]
[State]
[GroupNo]
[lastname]
As I said, you can do both. Here is a CTE you can use to generate the list for 3 years back. If the performance is not good enough, you should consider creating dedicated table.
WITH cte AS
(
SELECT 1 AS id, DATEPART(YEAR,GETDATE()) AS [year], DATEPART(MONTH,GETDATE()) AS [month]
UNION ALL
SELECT
id + 1 AS id,
CASE WHEN [month] = 1 THEN [year]-1 ELSE [year] END AS [year],
CASE WHEN [month] = 1 THEN 12 ELSE [month] - 1 END AS [month]
FROM cte WHERE id < 36
)
SELECT [Name], [year], [month]
FROM cte CROSS JOIN dbo.viewFranchiseList
Related
I am trying to figure out the aggregate functions in SQL SSRS to give me to sum of total sales for the given information by YEAR. I need to combine the year, the months within that year and provide the total sum of sales for that year. For example: for 2018 I need to combine month's 2-12 and provide the total sum, for 2019 combine 1-12 and provide total sum and so on.
enter image description here
I'm not sure where to begin on this one as I am new to SQL SSRS. Any help would be appreciated!
UPDATE:
Ideally I want this to be the end result:
id Year Price
102140 2019 ($XXXXX.XX)
102140 2018 ($XXXXX.XX)
102140 2017 ($XXXXX.XX)
And so on.
your query:
Select customer_id
, year_ordered
--, month_ordered
--, extended_price
--, SUM(extended_price) OVER (PARTITION BY year_ordered) AS year_total
, SUM(extended_price) AS year_total
From customer_order_history
Where customer_id = '101646'
Group By
customer_id
, year_ordered
, extended_price
--, month_ordered
Provides this:
enter image description here
multiple "years_ordered" because it is still using each month and that months SUM of price.
There are two approaches.
Do this in your dataset query:
SELECT Customer_id, year_ordered, SUM(extended_price) AS Price
FROM myTable
GROUP BY Customer_id, year_ordered
This option is best when you will never need the month values themselves in the report (i.e. you don't intend to have a drill down to the month data)
Do this in SSRS
By default you will get a RowGroup called "Details" (look under the main design area and you will row groups and column groups).
You can right-click this and add grouping for both customer_id and year_ordered. You can then change the extended_price textbox's value property to =SUM(Fields!extended_price.Value)
You could use a window function in your SQL:
select [year], [month], [price], SUM(PRICE) OVER (PARTITION BY year) as yearTotal
from myTable
I've just begun using Postgresql recently. I have a table named 'sales'.
create table sales
(
cust varchar(20),
prod varchar(20),
day integer,
month integer,
year integer,
state char(2),
quant integer
)
insert into sales values ('Bloom', 'Pepsi', 2, 12, 2001, 'NY', 4232);
insert into sales values ('Knuth', 'Bread', 23, 5, 2005, 'PA', 4167);
insert into sales values ('Emily', 'Pepsi', 22, 1, 2006, 'CT', 4404);
insert into sales values ('Emily', 'Fruits', 11, 1, 2000, 'NJ', 4369);
insert into sales values ('Helen', 'Milk', 7, 11, 2006, 'CT', 210);
...
There are 500 rows, 10 distinct products and 5 distinct customers in total.
It looks like this:
Now I need to , find the most “popular” and least “popular” products (those products with most and least total sales quantities) and the corresponding total sales quantities (i.e., SUMs) for each of the 12 months (regardless of the year).
The result should be like this:
Now I can only write query like this:
select month,
prod,
sum(quant)
from sales
group by month,prod
order by month,prod;
And it gives me the result like this:
Now I need to pick up the maximum value for each month. For example, the biggest value in the first 10 sums of month 1, and so on...
I also need to get the minimum value of the sums (regardless of the year). And combine them horizontally... I have no idea about this...
Note: for a TLDR, skip to the end.
Your problem is a very interesting textbook case as it involves multiple facets of Postgres.
I often find it very helpful to decompose the problem into multiple subproblems before joining them together for the final result set.
In your case, I see two subproblems: finding the most popular product for each month, and finding the least popular product for each month.
Let's start with the most popular products:
WITH months AS (
SELECT generate_series AS month
FROM generate_series(1, 12)
)
SELECT DISTINCT ON (month)
month,
prod,
SUM(quant)
FROM months
LEFT JOIN sales USING (month)
GROUP BY month, prod
ORDER BY month, sum DESC;
Explanations:
WITH is a common table
expression,
which acts as a temporary table (for the duration of the query) and
helps clarify the query. If you find it confusing, you could also opt
for a subquery.
generate_series(1, 12) is a Postgres function which generate a series of integers, in this case from 1 to 12.
the LEFT JOIN allows us to associate each sale to the corresponding month. If no sale can be found for a given month, a row is returned with the month and the joined columns with NULL values. More information on joins can be found here. In your case, using LEFT JOIN is important, as using INNER JOIN would exclude products that have never been sold (which in that case should be the least popular product).
GROUP BY is used to sum over the quantities.
at this stage, you should -potentially- have multiple products for any given month. We only want to keep those with the most quantities for each month. DISTINCT ON is especially useful for that purpose. Given a column, it allows us to keep the first iteration of each value. It is therefore important to ORDER the sales by sum first, as only the first one will be selected. We want the bigger numbers first, so DESC (for descending order) should be used.
We can now repeat the process for the least popular products:
WITH months AS (
SELECT generate_series AS month
FROM generate_series(1, 12)
)
SELECT DISTINCT ON (month)
month,
prod,
SUM(quant)
FROM months
LEFT JOIN sales USING (month)
GROUP BY month, prod
ORDER BY month, sum;
Conclusion (and TLDR):
Now we need to merge the two queries into one final query.
WITH months AS (
SELECT generate_series AS month
FROM generate_series(1, 12)
), agg_sales AS (
SELECT
month,
prod,
SUM(quant)
FROM months
LEFT JOIN sales USING (month)
GROUP BY month, prod
), most_popular AS (
SELECT DISTINCT ON (month)
month,
prod,
sum
FROM agg_sales
ORDER BY month, sum DESC
), least_popular AS (
SELECT DISTINCT ON (month)
month,
prod,
sum
FROM agg_sales
ORDER BY month, sum
)
SELECT
most_popular.month,
most_popular.prod AS most_popular_prod,
most_popular.sum AS most_pop_total_q,
least_popular.prod AS least_popular_prod,
least_popular.sum AS least_pop_total_q
FROM most_popular
JOIN least_popular USING (month);
Note that I used an intermediate agg_sales CTE to try and make the query a bit clearer and avoid repeating the same operation twice, although it shouldn't be a problem for Postgres' optimizer.
I hope you find my answer satisfactory. Do not hesitate to comment otherwise!
EDIT: although this solution should work as is, I would suggest storing your dates as a single column of type TIMESTAMPTZ. It is often much easier to manipulate dates using that type and it is always good practice in case you need to analyze and audit your database further down the line.
You can get the month of any date by simply using EXTRACT(MONTH FROM date).
I need to find a date that is 11 business days after a date.
I did not have a date table. Requested one, long lead time for one.
Used a CTE to produce results that have a datekey, 1 if weekday, and 1 if holiday, else 0. Put those results into a Table Variable, now Business_Day is (weekday-holiday). Much Googling has already happened.
select dt.Datekey,
(dt.Weekdaycount - dt.HolidayCount) as Business_day
from #DateTable dt[enter image description here][1]
UPDATE, I've figured it out in Excel. Running count of business days, a column of business day count + 11, then a Vlookup finding the +11 date . Now how do I do that in SQL?
Results like this
Datekey
2019-01-01
Business_day 0
Datekey
2019-01-02
Business_day
1
I will assume you want to set your weekdays, and you can enter the holidays in a variable table, so you can do the below:-
here set the weekend names
Declare #WeekDayName1 varchar(50)='Saturday'
Declare #WeekDayName2 varchar(50)='Sunday'
Set the holiday table variable, you may have it as a specific table your database
Declare #Holidays table (
[Date] date,
HolidayName varchar(250)
)
Lets insert a a day or two to test it.
insert into #Holidays values (cast('2019-01-01' as date),'New Year')
insert into #Holidays values (cast('2019-01-08' as date),'some other holiday in your country')
lets say your date you want to start from is action date and you need 11 business days after it
Declare #ActionDate date='2018-12-28'
declare #BusinessDays int=11
A recursive CTE to count the days till you get the correct one.
;with cte([date],BusinessDay) as (
select #ActionDate [date],cast(0 as int) BusinessDay
union all
select dateadd(day,1,cte.[date]),
case
when DATENAME(WEEKDAY,dateadd(day,1,cte.[date]))=#WeekDayName1
OR DATENAME(WEEKDAY,dateadd(day,1,cte.[date]))=#WeekDayName2
OR (select 1 from #Holidays h where h.Date=dateadd(day,1,cte.[date])) is not null
then cte.BusinessDay
else cte.BusinessDay+1
end BusinessDay
From cte where BusinessDay<#BusinessDays
)
--to see the all the dates till business day + 11
--select * from cte option (maxrecursion 0)
--to get the required date
select MAX([date]) from cte option (maxrecursion 0)
In my example the date I get is as below:-
ActionDate =2018-12-28
After 11 business days :2019-01-16
Hope this helps
1st step was to create a date table. Figuring out weekday verse weekends is easy. Weekdays are 1, weekends are 0. Borrowed someone else's holiday calendar, if holiday 1 else 0. Then Business day is Weekday-Holiday = Business Day. Next was to create a running total of business days. That allows you to move from whatever running total day you're current on to where you want to be in the future, say plus 10 business days. Hard coded key milestones in the date table for 2 and 10 business days.
Then JOIN your date table with your transaction table on your zero day and date key.
Finally this allows you to make solid calculations of business days.
WHERE CONVERT(date, D.DTRESOLVED) <= CONVERT(date, [10th_Bus_Day])
I'm using postgre .
Let's say there are 5 sellers .
Each month sale is recorded inside the database like this ( userId:6, january : 10000$, february:20000$ , march : 10000$ ... ,december:50000$, year :2018 )
I need to calculate , possibily with only one query, the best of each month sale in one array of this format : ( january : 15000$, february:30000$ , march : 40000$ , year :2018 ), i dont need the userId . I simply need to compare each sales per months and display the best amount ...
For now, i've got this code, who works well, givin me the user 6 sales per month on a given year :
SELECT date_trunc('month', date_vente) AS txn_month, sum(prix_vente) as monthly_sum,count(prix_vente) AS monthly_count
FROM crm_vente
WHERE 1=1
AND date_part('year', date_vente) = 2018
AND id_user = 6
GROUP BY txn_month ORDER BY txn_month
I wonder if somebody could tell me what kind of technology i could use to get the best of sales each 12 months between of the 5 employees .
COuld i use view ? SHould i better do a for loop in php, with each of the users sales per months, then do a kind of comparative array ?
No need to give me a full resolution, but maybe an advice on how to do, directly with postgre ? Because my only solution for now is to use php and to do a not nice code .
Nice day, ill check on MOnday
Sorry for my english
WITH monthly_sales AS (
SELECT
date_trunc('month', date_vente) AS txn_month,
user_id,
sum(prix_vente) as monthly_sum,
FROM crm_vente
WHERE 1=1
AND date_part('year', date_vente) = 2018
GROUP BY txn_month, user_id
ORDER BY txn_month, user_id),
rank_monthly_sales_by_user_id AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY txn_month ORDER BY monthly_sum DESC) AS rank
FROM monthly_sales)
SELECT
txn_month,
monthly_sum
FROM rank_monthly_sales_by_user_id
WHERE rank = 1
ORDER BY txn_month ASC;
Firstly what you should do is get the totals per month by user. This is the top subquery called monthly sales. Monthly_sales sums the sales of each user by month
Next, to get the top user for each month in terms of their total sales you have to rank the rows returned by the previous subquery. This is down by ROW_NUMBER()
ROW_NUMBER() gets the row number in a specified window, in this case it's ordering the rows from monthly_sales for each month (it starts ordering again from 1 each month). The PARTITION BY statement is the window in which we want to perform the row count, here it's month since we want to order our user_id's sales by month. The ORDER BY statement says how to order the rows from 1 to n. We're using monthly_sum in descending order. So the highest monthly sum is 1, lowest is 6
The next query is selecting only the rows from rank_monthly_sales_by_user_id that are the top sales for the month (WHERE rank = 1)
This leaves us with a output where is row is a month, with the highest sale for that month
Let me know if that was what you needed help with
Hello colleagues I have a question about a query if it could be done I have a table called sale and a field called sales_date, so the field is full more or less like this
--------------------------------------------------
sales_date
--------------------------------------------------
2013-02-03
2013-02-05
2014-06-07
2015-03-04
2015-01-04
2016-04-07
2016-09-03
2016-04-09
And I would like to know how to do a select and show me only the years without repeating
--------------------------------------------------
sales_date
--------------------------------------------------
2013
2014
2015
2016
Thanks any help, my database is in Postgresql version 9.5.
You can use extract() to get the year and distinct to remove the duplicates:
select distinct extract(year from sales_date) as sales_date
from sale;