How to get the total sales of immediate subordinate based on sales of all subordinate in charge in SQL Server? - sql-server-2005

the structure is as follows:
ID_EMPLOYEE ID_EMPLOYEE_BOSS LEVEL
-------------------------------------------
100 NULL 1
201 100 2
202 100 2
301 201 3
302 201 3
303 202 3
304 202 3
401 302 4
402 302 4
403 302 4
N N-1 N
And structure for sales
ID_EMPLOYEE SALE DATE
401 1100.00 2015-06-07
402 1500.00 2015-06-05
403 1400.00 2015-06-25
303 5000.00 2015-05-25
304 8250.00 2015-05-25
I tried this
WITH Sales_CTE (ID_EMPLOYEE, SALE, MONTHS)
AS
(
SELECT ID_EMPLOYEE, sum(SALE), DATEPART(mm,DATE)
FROM SALES
GROUP BY ID_EMPLOYEE, DATEPART(mm,DATE)
)
SELECT JE.ID_EMPLOYEE, OS.SALE, OS.MONTHS,
JE.ID_EMPLOYEE_BOSS, OM.SALE, OM.MONTHS
FROM EMPLOYEES AS JE
JOIN Sales_CTE AS OS
ON JE.ID_EMPLOYEE= OS.ID_EMPLOYEE
LEFT OUTER JOIN Sales_CTE AS OM
ON JE.ID_EMPLOYEE_BOSS= OM.ID_EMPLOYEE
WHERE ID_EMPLOYEE_BOSS= 302
ORDER BY JE.ID_EMPLOYEE_BOSS;
Currently only I can see sales employee level n-1 immediate, but I want to show as follows. For example employee 100 can see
ID_EMPLOYEE SALES MONTH
201 4000 6
202 13250 5
This n levels

Prepare schema
CREATE TABLE STRUCTURE(ID_EMPLOYEE INT, ID_EMPLOYEE_BOSS INT, LEVEL INT)
CREATE TABLE SALES(ID_EMPLOYEE INT,SALE INT,DDATE DATE)
Prepare data
INSERT INTO STRUCTURE VALUES (100,NULL,1)
INSERT INTO STRUCTURE VALUES (201,100, 2)
INSERT INTO STRUCTURE VALUES (202,100, 2)
INSERT INTO STRUCTURE VALUES (301,201, 3)
INSERT INTO STRUCTURE VALUES (302,201, 3)
INSERT INTO STRUCTURE VALUES (303,202, 3)
INSERT INTO STRUCTURE VALUES (304,202, 3)
INSERT INTO STRUCTURE VALUES (401,302, 4)
INSERT INTO STRUCTURE VALUES (402,302, 4)
INSERT INTO STRUCTURE VALUES (403,302, 4)
INSERT INTO SALES VALUES(401,1100.00,'2015-06-07')
INSERT INTO SALES VALUES(402,1500.00,'2015-06-05')
INSERT INTO SALES VALUES(403,1400.00,'2015-06-25')
INSERT INTO SALES VALUES(303,5000.00,'2015-05-25')
INSERT INTO SALES VALUES(304,8250.00,'2015-05-25')
Query
WITH Sales_CTE
AS
(
SELECT ID_EMPLOYEE,ID_EMPLOYEE_BOSS,ID_EMPLOYEE AS ROOTID
FROM STRUCTURE
WHERE ID_EMPLOYEE_BOSS=100
UNION ALL
SELECT S.ID_EMPLOYEE,S.ID_EMPLOYEE_BOSS,SC.ROOTID
FROM STRUCTURE S
INNER JOIN Sales_CTE SC ON SC.ID_EMPLOYEE = S.ID_EMPLOYEE_BOSS
)
SELECT SC.ROOTID AS ID_EMPLOYEE,SUM(S.SALE) AS SALES,MONTH(S.DDATE) AS [MONTH]
FROM Sales_CTE SC
INNER JOIN SALES S ON S.ID_EMPLOYEE = SC.ID_EMPLOYEE
GROUP BY SC.ROOTID,MONTH(S.DDATE)
ORDER BY SC.ROOTID,MONTH(S.DDATE)
SQL Fiddle : http://sqlfiddle.com/#!3/b641d/1

Related

HANA SQL Filling missing gaps in a date table with balance history

On Hana Sql environment I have this table with changes of balances from customers accounts by dates:
"BalanceTable"
CustomerID
BalDate
Balance
1
2021-06-01
0
1
2021-06-04
100
1
2021-06-28
500
2
2021-06-01
200
2
2021-06-03
0
2
2021-07-02
300
...
The table has several rows.
I have created now a date table with all the dates of the interval using the earliest day as first row and latest day as last row:
"DateTable"
Day
2021-06-01
2021-06-02
2021-06-03
2021-06-04
2021-06-05
2021-06-06
...
2021-07-02
I need to join the two tables having the daily balance of each customer:
Day
CustomerID
Balance
2021-06-01
1
0
2021-06-02
1
0
2021-06-03
1
0
2021-06-04
1
100
2021-06-05
1
100
2021-06-06
1
100
...
2021-06-27
1
100
2021-06-28
1
500
2021-06-29
1
500
2021-06-30
1
500
2021-07-01
1
500
2021-07-02
1
100
2021-06-01
2
200
2021-06-02
2
200
2021-06-03
2
0
2021-06-04
2
0
2021-06-05
2
0
...
2021-06-30
2
0
2021-07-01
2
0
2021-07-02
2
300
As first aproach I have tried joining the two tables using a left join:
SELECT * FROM "DateTable" T0 LEFT JOIN "BalanceTable" T1 ON T0."Day"=T1."BalDate"
But I know the proper solution is far beyond my limited SQL knowledge. The key is being able to fill in the gaps for the days of the "DateTable" that don't have a balance value in the "BalanceTable" with the balance of the previous last day with data.
I've read similar cases and they combine IFNULL function to fill gaps with PARTITION BY clause to get the last value, but after many attempts I wasn't able to apply that to my case.
Thank you for your ideas and sorry if I miss something, this is my first post asking for help.
So you have this example data:
CREATE TABLE BALANCETAB (CUSTOMERID INTEGER, BALDATE DATE, BALANCE INTEGER);
INSERT INTO BALANCETAB VALUES (1, '2021-06-01', 0);
INSERT INTO BALANCETAB VALUES (1, '2021-06-04', 100);
INSERT INTO BALANCETAB VALUES (1, '2021-06-28', 500);
INSERT INTO BALANCETAB VALUES (2, '2021-06-01', 200);
INSERT INTO BALANCETAB VALUES (2, '2021-06-03', 0);
INSERT INTO BALANCETAB VALUES (1, '2021-07-02', 300);
You already headed in the right direction by creating the dates table:
CREATE TABLE DATETAB AS (
SELECT GENERATED_PERIOD_START DAY
FROM SERIES_GENERATE_DATE('INTERVAL 1 DAY', '2021-06-01' ,'2021-07-02')
);
However, additionally you will need to know all customers since you want to add one row per date and per customer (cross join):
CREATE TABLE CUSTOMERTAB AS (
SELECT DISTINCT CUSTOMERID FROM BALANCETAB
);
From this you can infer the table with NULL values, that you would like to fill:
WITH DATECUSTOMERTAB AS (
SELECT * FROM DATETAB, CUSTOMERTAB
)
SELECT DCT.DAY, DCT.CUSTOMERID, BT.BALANCE
FROM DATECUSTOMERTAB DCT
LEFT JOIN BALANCETAB BT ON DCT.DAY = BT.BALDATE AND DCT.CUSTOMERID = BT.CUSTOMERID
ORDER BY DCT.CUSTOMERID, DCT.DAY;
On this table, you can apply a self-join (BTFILL) and use window function RANK (documentation) to determine the latest previous balance value.
WITH DATECUSTOMERTAB AS (
SELECT * FROM DATETAB, CUSTOMERTAB
)
SELECT DAY, CUSTOMERID, IFNULL(BALANCE, BALANCEFILL) BALANCE_FILLED
FROM
(
SELECT DCT.DAY, DCT.CUSTOMERID, BT.BALANCE, BTFILL.BALANCE AS BALANCEFILL,
RANK() OVER (PARTITION BY DCT.DAY, DCT.CUSTOMERID, BT.BALANCE ORDER BY BTFILL.BALDATE DESC) RNK
FROM DATECUSTOMERTAB DCT
LEFT JOIN BALANCETAB BT ON DCT.DAY = BT.BALDATE AND DCT.CUSTOMERID = BT.CUSTOMERID
LEFT JOIN BALANCETAB BTFILL ON BTFILL.BALDATE <= DCT.DAY AND DCT.CUSTOMERID = BTFILL.CUSTOMERID AND BTFILL.BALANCE IS NOT NULL
)
WHERE RNK = 1
ORDER BY CUSTOMERID, DAY;
Of course, you would omit the explicit creation of tables DATETAB and CUSTOMERTAB. The list of expected customer would probably already exist somewhere in your system and the series generator function could be part of the final statement.

How to insert values into the following table by incrementing the date column by 1 day for the next 23 days?

I am using SQL Server 2014. I have a table names T1 (extract shown below):
Company ReviewDate Rank Type Reviews
...
A 2020-10-12 8 Hotel 675
B 2020-10-12 10 Hotel 450
C 2020-10-12 21 Hotel 89
D 2020-10-12 60 Hotel 1200
A 2020-10-13 5 Hotel 688
B 2020-10-13 10 Hotel 500
C 2020-10-13 21 Hotel 89
D 2020-10-13 60 Hotel 1200
I need to update table T1 for period 2020-10-13 to 2020-11-04 with the following logic: All rows to be appended to the table will have the same values as those for ReviewDate on 2020-10-12 except the ReviewDate which will increment by 1 day until 2020-11-04 is reached.
So here is an extract of how the final table will look like (only appended ReviewDate 2020-10-13 shown:
Company ReviewDate Rank Type Reviews
...
A 2020-10-11 8 Hotel 675
B 2020-10-11 10 Hotel 450
C 2020-10-11 21 Hotel 89
D 2020-10-11 60 Hotel 1200
A 2020-10-12 5 Hotel 688
B 2020-10-12 10 Hotel 500
C 2020-10-12 21 Hotel 89
D 2020-10-12 60 Hotel 1200
A 2020-10-13 5 Hotel 688
B 2020-10-13 10 Hotel 500
C 2020-10-13 21 Hotel 89
D 2020-10-13 60 Hotel 1200
...
NOTE: the table also contain entries with ReviewDate before 2020-10-12 but I just need to insert values into the table for a specific period with data related to 2020-10-12
How can I do that with a T-SQL query?
You need to insert rows. One method is to cross join to the dates you want and use that:
insert into t1 (Company, ReviewDate, Rank, Type, Reviews)
select t1.Company, v.date, t1.Rank, t1.Type, t1.Reviews
from t1 cross join
(values ('2020-10-13'), ('2020-10-14'), . . .
) v(date
where t1.reviewdate = '2020-10-12';
There are other ways to create the dates. One method is a recursive CTE:
with dates as (
select convert(date, '2020-10-13') as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < '2020-11-04'
)
select . . .
from t1 cross join
dates d;
Try this code.
DECLARE #TABLE TABLE (
COMPANY VARCHAR(1),
ReviewDate Date,
[Rank] int
)
INSERT INTO #TABLE VALUES ('A','2020-10-11',5)
INSERT INTO #TABLE VALUES ('B','2020-10-11',10)
INSERT INTO #TABLE VALUES ('C','2020-10-11',21)
INSERT INTO #TABLE VALUES ('D','2020-10-11',60)
;WITH CTE AS (
SELECT * FROM #TABLE
UNION ALL
SELECT
COMPANY,
dateadd(day,1,ReviewDate),
[Rank]
from CTE
WHERE ReviewDate <= '2020-10-13'
)
SELECT * FROM CTE
ORDER BY 2,1

Need a SQL insert query for a table from a temporary table without duplication

I need to insert into a table from a temporary table without duplicating the data from temp table. ie , for each customer need to insert a single row with SpecialCreditNoteAwarded
My temporary table:
CustID SalesMasterID SpecialCreditNoteAwarded
------------------------------------------------
100 13139 92115
100 13148 92115
100 13150 92115
101 13204 1175
101 13205 1175
102 13209 650
102 13210 650
102 13211 650
Result table
CustID SaleID SpecialCreditNoteAwarded
-----------------------------------------
100 0 92115
101 0 1175
102 0 650
You can use the GROUP BY function in a SELECT statement to remove duplicates
INSERT INTO Table_rslt (CustID, SaleID, SpecialCreditNoteAwarded)
SELECT
CustID
,0
,SpecialCreditNoteAwarded
FROM #temp
GROUP BY CustID,SpecialCreditNoteAwarded;
You didn't specify your DBMS, so this answer is for SQL SERVER.

Subtract from purchase and sale s table for found balance

I have two tables: table one Purchase and another sales table, actually I need balance using subtract two table, subtract sales from table Purchase. My code is given below
create table purchase(
id number(10) primary key,
name varchar2(10),
p_qty number(10)
);
and insert data :
insert into purchase values(01,'productB',235);
insert into purchase values(04,'productC',394);
insert into purchase values(05,'productD',381);
insert into purchase values(08,'productE',357);
insert into purchase values(09,'productF',389);
insert into purchase values(10,'productQ',336);
another table: Sales
create table sales(
id number(10),
s_qty number(10),
constraint pid_pk foreign key (id)REFERENCES purchase(id)
);
insert data to salse table :
insert into sales values(01,34);
insert into sales values(04,54);
insert into sales values(05,44);
insert into sales values(09,50);
insert into sales values(01,3);
insert into sales values(04,4);
insert into sales values(05,5);
insert into sales values(09,53);
insert into sales values(01,2);
insert into sales values(04,2);
insert into sales values(05,2);
insert into sales values(09,2);
insert into sales values(01,4);
insert into sales values(04,9);
insert into sales values(05,11);
insert into sales values(09,7);
and I have using two query
Query 1:
select id,name,sum(p_qty) as p_total from purchase group by id,name;
ID NAME P_TOTAL
5 productD 381
10 productQ 336
4 productC 394
1 productB 235
8 productE 357
9 productF 389
QUERY2:
select id,sum(s_qty) as s_total from sales group by id;`
ID S_TOTAL
1 43
4 69
5 62
9 112
NOW I Want to below the table for balance each item
ID NAME P_TOTAL S_TOTAL BALANCE
5 productD 381 62 319
4 productC 394 69 325
1 productB 235 43 192
9 productF 389 112 277
Hope this helps.
SELECT p.id, p.name, p.p_total, s.s_total,
p.p_total - s.s_total AS balance
FROM (select id, name, sum(p_qty) as p_total FROM purchase
GROUP BY id, name) p
INNER JOIN (select id, sum(s_qty) as s_total FROM sales
GROUP BY id) s
ON s.ID = p.ID;
You're almost there. Take the two queries you already have and join them together:
SELECT p.ID,
p.NAME,
p.P_TOTAL,
s.S_TOTAL,
p.P_TOTAL - s.S_TOTAL AS BALANCE
FROM (select id, name, sum(p_qty) as p_total
from purchase
group by id, name) p
INNER JOIN (select id, sum(s_qty) as s_total
from sales
group by id) s
ON s.ID = p.ID
Best of luck.
I Want to below the table for balance each item
You way you want the balance for each item, but you only show the balance for the items with sales.
If you want each item that has been purchased, you can use left join with subqueries:
select p.id, p.name, p_total, coalesce(s_total, 0),
(p_total - coalesce(s_total, 0)) as balance
from (select id, name, sum(p_qty) as p_total
from purchase
group by id,name
) p left join
(select id, sum(s_qty) as s_total
from sales
group by id
) s
on p.id = s.id;
If you want each item that has sales, then just use inner join.

T SQL to join record dynamically

Can someone help me out with the following scenario. I am using SQL Server 2008r2. I need sql server query to get the expected result. Here is what I tried to do:
DECLARE #ProjectInvoice TABLE(InvoiceID INT, ProjectID INT, InvoiceAmount float)
DECLARE #ProjectBudget TABLE(ProjectBudgetID INT, ProjectID INT, BudgetAmount float)
INSERT INTO #ProjectBudget VALUES(11,1,100000),(12,1,50000)
INSERT INTO #ProjectInvoice VALUES (12345,1,25000)
,(12346,1, 30000)
,(12347,1, 40000)
,(12348,1, 30000)
,(12349,1, 10000)
select * from #ProjectBudget
select * from #ProjectInvoice
Expected result:
-- Expected Result
--InvoiceID ProjectID InvoiceAmount ProjectBudgetID BugetAmountLeft
-- 12345 1 25k 11 75k -- > 100k(original budget) - 25k
-- 12346 1 30k 11 45k --> 75k( budget amount left after first invoice) - 30k
-- 12347 1 40k 11 5k --> 45k - 40k
-- 12348 1 5k 11 0k --> now only 5k is left budget, whereas we have 30k to deduct, deduct 5k from projectBudget11
-- 12348 1 25k 12 25k --> and the rest 25k from project Budget 12
-- 12349 1 10k 12 15k
SELECT p.InvoiceID, p.ProjectID, p.InvoiceAmount, sm.ProjectBudgetID,
sm.BudgetAmount - sm.amt AS runningTot
FROM #ProjectInvoice AS p
INNER JOIN (SELECT i.InvoiceID, b.projectBudgetID, b.BudgetAmount,
SUM(i.InvoiceAmount) OVER (PARTITION BY b.ProjectBudgetID ORDER BY
i.InvoiceId) AS amt
FROM #ProjectBudget AS b
INNER JOIN #ProjectInvoice AS i ON b.ProjectID = i.ProjectID) as sm ON p.InvoiceID = sm.InvoiceId