Joining two tables and producing results only on one table when there are null values on joining column - sql

I have table Quota with columns 'Month Number', 'year','Goal' as below
I have other table Sales with columns 'id', 'Sale Date' as below.
I am joining both the tables on Month and year of 'sales date' from Sales table to 'Month Number' and 'year' from Quota Table to get the results and i am able to get results if i have sales for that particular month and year.Now for the month of may i have no sales so when i join on those columns i am not getting any results from quota table. how can i just display Quota table values if there are no corresponding sales in Sales table? I tried left joining but its not displaying any results.

Like already said, we don't know your desired output. But by using a left join you should retrieve the records from the quota table.
declare #quota table (monthnumber int, qyear int, goal int)
insert into #quota values
(2,2017,5),
(3,2017,10),
(4,2017,8),
(5,2017,8),
(6,2017,10)
declare #sales table (id int, salesdate date)
insert into #sales values
(101,'20170321'),
(102,'20170427'),
(103,'20170223'),
(105,'20170427'),
(108,'20170321'),
(109,null),
(111,null)
select q.*
from #quota as q
left outer join #sales as s
on year(s.salesdate) = q.qyear and
month(s.salesdate) = q.monthnumber
Returns
monthnumber qyear goal
--------------------------
2 2017 5
3 2017 10
3 2017 10
4 2017 8
4 2017 8
5 2017 8
6 2017 10

You can use month and year of function and do left join as below
select * from Quota q left join sales s
on q.year = year(s.saledate) and q.MonthNumber = month(s.saledate)

Despite you didn't specify what output you need or your effort so far, I made my attempt anyway and I guess this is what you want:
SELECT
Q.*,
SalesCount = (SELECT COUNT(*) FROM Sales S
WHERE YEAR(S."Sale Date") = Q.Year AND MONTH(S."Sale Date") = Q.MonthNumber)
FROM Quota Q
And this is the result:
MonthNumber Year Goal SalesCount
2 2017 5 1
3 2017 10 2
4 2017 8 2
5 2017 8 0
6 2017 10 0

Related

Displaying results for fixed values in SQL

I am having difficulty in solving the below problem:
I have a table which contains the shopid, date, hour, category and sales amount.
shopid date hour category amount
------------------------------------
1 date1 7 food 10
1 date1 8 food 15
1 date1 10 misc. 5
2 date1 7 food 6
...................................
I am trying to calculate the total sales amount in each hour by food category and display like the following:
shopid category hour amount
------------------------------------
1 food 6 0
1 food 7 5
1 food 8 20
2 food 9 40
...................................
The shops' opening hours are 6 am -10 pm. So for each hour, there might be any sales or not. I was able to perform the hourly summation. But I am unable to display zero and the time when there are no sales at a particular time (e.g. 6 am or any other time between the opening hours) for each sale category.
Use a left join against a list of hours:
select t.shopid, t.category. g.hour, sum(t.amount)
from generate_series(6,22) as g(hour)
left join the_table t on t.hour = g.hour
group by t.shopid, t.category, g.hour
order by t.shopid, t.category, g.hour;
I am trying to calculate the total sales amount in each hour by food category.
This makes sense, but it doesn't make sense to include the shopid in the results.
To do this, you need to generate the rows -- which are all hours and food categories. Then bring in the actual results using left join:
select c.category. g.hour, coalesce(sum(s.amount), 0)
from generate_series(6, 22) g(hour) cross join
(select distinct category from sales) c left join
sales s
on s.hour = g.hour and s.category = c.category
group by c.category, g.hour
order by c.category, g.hour;
If you want results by shop/category/hour, then you can use the same idea:
select sh.shopid, c.category. g.hour,
coalesce(sum(s.amount), 0)
from generate_series(6, 22) g(hour) cross join
(select distinct category from sales) c cross join
(select distinct shopid from sales) sh left join
sales s
on s.shopid = sh.shopid and
s.hour = g.hour and
s.category = c.category
group by sh.shopid, c.category, g.hour
order by sh.shopid, c.category, g.hour;

SQL server 2012 - group by month, 3 month, 6 months, 11 months and prior year 11 months

Trying to build a query to have sum on sales column by month, 3 months, 6 months, 11 months and prior year 11 months. What are possible options to go about it.
I tried datediff and date related functions didn't get intended results.
Would like some suggestions on how to go about it?
This should get you started.
CREATE TABLE sales (
product varchar (1),
month int,
amount int
)
insert into sales values ('a',1,5); insert into sales values ('a',1,33);
insert into sales values ('a',2,32); insert into sales values ('b',1,12);
insert into sales values ('b',2,4); insert into sales values ('c',1,5);
insert into sales values ('c',2,11); insert into sales values ('c',2,13);
SELECT
product,
SUM(CASE WHEN month = 1 THEN amount END) AS Month1,
SUM(CASE WHEN month = 2 THEN amount END) AS Month2
FROM
sales
GROUP BY
product
output:
product | Month1 | Month2
--------------------------------
a | 38 | 32
b | 12 | 4
c | 5 | 24

Aggregate payments per year per customer per type

Please consider the following payment data:
customerID paymentID pamentType paymentDate paymentAmount
---------------------------------------------------------------------
1 1 A 2015-11-28 500
1 2 A 2015-11-29 -150
1 3 B 2016-03-07 300
2 4 A 2015-03-03 200
2 5 B 2016-05-25 -100
2 6 C 2016-06-24 700
1 7 B 2015-09-22 110
2 8 B 2016-01-03 400
I need to tally per year, per customer, the sum of the diverse payment types (A = invoice, B = credit note, etc), as follows:
year customerID paymentType paymentSum
-----------------------------------------------
2015 1 A 350 : paymentID 1 + 2
2015 1 B 110 : paymentID 7
2015 1 C 0
2015 2 A 200 : paymentID 4
2015 2 B 0
2015 2 C 0
2016 1 A 0
2016 1 B 300 : paymentID 3
2016 1 C 0
2016 2 A 0
2016 2 B 300 : paymentID 5 + 8
2016 2 C 700 : paymentId 6
It is important that there are values for every category (so for 2015, customer 1 has 0 payment value for type C, but still it is good to see this).
In reality, there are over 10 payment types and about 30 customers. The total date range is 10 years.
Is this possible to do in only SQL, and if so could somebody show me how? If possible by using relatively easy queries so that I can learn from it, for instance by storing intermediary result into a #temptable.
Any help is greatly appreciated!
a simple GROUP BY with SUM() on the paymentAmount will gives you what you wanted
select year = datepart(year, paymentDate),
customerID,
paymentType,
paymentSum = sum(paymentAmount)
from payment_data
group by datepart(year, paymentDate), customerID, paymentType
This is a simple query that generates the required 0s. Note that it may not be the most efficient way to generate this result set. If you already have lookup tables for customers or payment types, it would be preferable to use those rather than the CTEs1 I use here:
declare #t table (customerID int,paymentID int,paymentType char(1),paymentDate date,
paymentAmount int)
insert into #t(customerID,paymentID,paymentType,paymentDate,paymentAmount) values
(1,1,'A','20151128', 500),
(1,2,'A','20151129',-150),
(1,3,'B','20160307', 300),
(2,4,'A','20150303', 200),
(2,5,'B','20160525',-100),
(2,6,'C','20160624', 700),
(1,7,'B','20150922', 110),
(2,8,'B','20160103', 400)
;With Customers as (
select DISTINCT customerID from #t
), PaymentTypes as (
select DISTINCT paymentType from #t
), Years as (
select DISTINCT DATEPART(year,paymentDate) as Yr from #t
), Matrix as (
select
customerID,
paymentType,
Yr
from
Customers
cross join
PaymentTypes
cross join
Years
)
select
m.customerID,
m.paymentType,
m.Yr,
COALESCE(SUM(paymentAmount),0) as Total
from
Matrix m
left join
#t t
on
m.customerID = t.customerID and
m.paymentType = t.paymentType and
m.Yr = DATEPART(year,t.paymentDate)
group by
m.customerID,
m.paymentType,
m.Yr
Result:
customerID paymentType Yr Total
----------- ----------- ----------- -----------
1 A 2015 350
1 A 2016 0
1 B 2015 110
1 B 2016 300
1 C 2015 0
1 C 2016 0
2 A 2015 200
2 A 2016 0
2 B 2015 0
2 B 2016 300
2 C 2015 0
2 C 2016 700
(We may also want to play games with a numbers table and/or generate actual start and end dates for years if the date processing above needs to be able to use an index)
Note also how similar the top of my script is to the sample data in your question - except it's actual code that generates the sample data. You may wish to consider presenting sample code in such a way in the future since it simplifies the process of actually being able to test scripts in answers.
1CTEs - Common Table Expressions. They may be thought of as conceptually similar to temp tables - except we don't actually (necessarily) materialize the results. They also are incorporated into the single query that follows them and the whole query is optimized as a whole.
Your suggestion to use temp tables means that you'd be breaking this into multiple separate queries that then necessarily force SQL to perform the task in an order that we have selected rather than letting the optimizer choose the best approach for the above single query.

Mondrian MDX Last Element Aggregation

In TelCo industry is very important to know what was the customer status at some some point (end of week, month, etc).
So, I have SDC type II dimension with: customer_tk, customerID, status, date.
We use it custom reports to find what is state on some day (example):
Date = '2015-10-01'
Group Active Terminated Suspended Order
------------------------------------------------------
Group1 25 2 2 8
Group2 45 8 0 12
Group3 15 18 5 2
Group4 65 2 1 29
This is pivoted from query:
SELECT * FROM dim_customer
INNER JOIN (SELECT max(customer_tk) as maxId, customerId FROM dim_customer WHERE date<='2015-10-01' GROUP BY customerId) as maxCust
ON dim_customer.customer_tk = maxCust.maxId
And it works perfectly (date is parameter from report).
I want to put it in cube but how to create this type of join? I need cumulative count of customers
I tried with MDX Tail(filter(... )) expressions but didn't managed to get correct numbers.
So, basically, with no filters, it should return status = 8 for customer 29841 and status = 2 for customer 28425.
But if choose year = 2014, it should return status = 2 for both customers:
Thanks

Generate year to date by month report in SQL [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Running total by grouped records in table
I am trying to put together an SQL statement that returns the SUM of a value by month, but on a year to date basis. In other words, for the month of March, I am looking to get the sum of a value for the months of January, February, and March.
I can easily do a group by to get a total for each month by itself, and potentially calculate the year to date value I need in my application from this data by looping through the results set. However, I was hoping to have some of this work handled with my SQL statement.
Has anyone ever tackled this type of problem with an SQL statement, and if so, what is the trick that I am missing?
My current sql statement for monthly data is similar to the following:
Select month, year, sum(value) from mytable group by month, year
If I include a where clause on the month, and only group by the year, I can get the result for a single month that I am looking for:
select year, sum(value) from mytable where month <= selectedMonth group by year
However, this requires me to have a particular month pre-selected or to utilize 12 different SQL statements to generate one clean result set.
Any guidance that can be provided would be greatly appreciated!
Update: The data is stored on an IBM iSeries.
declare #Q as table
(
mmonth INT,
value int
)
insert into #Q
values
(1,10),
(1,12),
(2,45),
(3,23)
select sum(January) as UpToJanuary,
sum(February)as UpToFebruary,
sum(March) as UpToMarch from (
select
case when mmonth<=1 then sum(value) end as [January] ,
case when mmonth<=2 then sum(value) end as [February],
case when mmonth<=3 then sum(value) end as [March]
from #Q
group by mmonth
) t
Produces:
UpToJanuary UpToFebruary UpToMarch
22 67 90
You get the idea, right?
NOTE: This could be done easier with PIVOT tables but I don't know if you are using SQL Server or not.
As far as I know DB2 does support windowing functions although I don't know if this is also supported on the iSeries version.
If windowing functions are supported (I believe IBM calls them OLAP functions) then the following should return what you want (provided I understood your question correctly)
select month,
year,
value,
sum(value) over (partition by year order by month asc) as sum_to_date
from mytable
order by year, month
create table mon
(
[y] int not null,
[m] int not null,
[value] int not null,
primary key (y,m))
select a.y, a.m, a.value, sum(b.value)
from mon a, mon b
where a.y = b.y and a.m >= b.m
group by a.y, a.m, a.value
2011 1 120 120
2011 2 130 250
2011 3 500 750
2011 4 10 760
2011 5 140 900
2011 6 100 1000
2011 7 110 1110
2011 8 90 1200
2011 9 70 1270
2011 10 150 1420
2011 11 170 1590
2011 12 600 2190
You should try to join the table to itself by month-behind-a-month condition and generate a synthetic month-group code to group by as follows:
select
sum(value),
year,
up_to_month
from (
select a.value,
a.year,
b.month as up_to_month
from table as a join table as b on a.year = b.year and b.month => a.month
)
group by up_to_month, year
gives that:
db2 => select * from my.rep
VALUE YEAR MONTH
----------- ----------- -----------
100 2011 1
200 2011 2
300 2011 3
400 2011 4
db2 -t -f rep.sql
1 YEAR UP_TO_MONTH
----------- ----------- -----------
100 2011 1
300 2011 2
600 2011 3
1000 2011 4