MS ACCESS Cross table DATA - sql

I have two tables, one with employee details looks like this
Employee ID | Employee Name | Start Date | Termination Date |
2234 | John Smith | 2014-01-03 | |
3333 | Jane Doe | 2014-04-22 | 2014-10-31 |
1234 | Bobby Wilson | 2013-12-10 | |
My second table has there sales by month-year
looks like so
Employee ID | 2013-12 | 2014-01 | 2014-02 | 2014-03 | 2014-04 | etc | etc
2234 | | 199.99 | 130.00 | 300.00 | 230.99 | etc | etc
3333 | | | | | 204.02 | etc | etc
1234 | 455.99 | 332.32 | 334.00 | 553.00 | 334.99 | etc | etc
So what i need is to make a new Query that helps me show the trend of the employee on how their first month employeed sales number looks like, second month sales, third moneth sales etc. based on when the month one being when the employee started. Over a spand of 12 month or more
So the new table would look as follows
Employee | Month 1 | Month 2 | Month 3 | Month 4 | etc | etc |
2234 | 199.99 | 130.00 | 300.00 | 230.99 | etc | etc |
3333 | 240.02 | (month 2) | (month 3)| (month 4)| etc | etc |
1234 | 455.99 | 332.32 | 334.00 | 553.00 | etc | etc |
So I know we can join the two tables by Employee ID
and I know we can determine an employee's month one based on their start date
but how do you write this query out in SQL?

As i mentioned in my comment to the question, you need to change the design of your second table as follow (pseudo-code):
CREATE TABLE Sales(
SaleId Autonumber PK
[Employee ID] FK (reference to Employees table)
SalesDate DateTime
Sales Decimal/Double
);
Then you'll be able to save your data this way:
SaleID EmpId SalesDate Sales
1 2234 2014-01-01 199,99
2 1234 2013-12-01 455.99
3 1234 2014-01-01 332.32
4 2234 2014-02-01 130
5 1234 2014-02-01 334
6 2234 2014-03-01 300
7 1234 2014-03-01 553
8 2234 2014-04-01 230.99
9 3333 2014-04-01 204.02
10 1234 2014-04-01 334.99
Finally, your pivot table might look like:
TRANSFORM Sum(S.Sales) AS SumOfSales
SELECT E.[Employee Id], E.[Employee Name]
FROM Employees AS E INNER JOIN SalesByMY AS S
ON E.[Employee Id] = S.[Employee Id]
GROUP BY E.[Employee Id], E.[Employee Name]
PIVOT 'Month-' & DateDiff('m',[E].[StartDate],[S].[SalesDate])+1;
The result:
EmpId EmpName Month-1 Month-2 Month-3 Month-4 Month-5
1234 Bobby Wilson 455.99 332.32 334 553 334.99
2234 John Smith 199.99 130 300 230.99
3333 Jane Doe 204.02

Related

How can I SELECT MAX(VALUE) from duplicate values which occur multiple time within each month?

I have records for each user which occur multiple times each month. I wish to select just the highest value from the repeated values for each month for each user.
Table schema
custacc
ID | ac_no | DODSTART | od_limit
---+--------+------------+----------
1 | 110011 | 2019-02-10 | 200,000
2 | 110011 | 2019-02-12 | 120,000
3 | 110014 | 2019-02-10 | 70,000
4 | 110014 | 2019-02-12 | 10,000
5 | 110009 | 2019-02-10 | 30,000
customer
ID | cust_no | name | cust_type
---+---------+-------+----------
1 | 110011 | Jame | M
2 | 110014 | Fred | N
3 | 110009 | Ahmed | M
How can I achieve this>
What I tried so far:
SELECT
custacc.ac_no,
custacc.od_limit,
custacc.DODSTART,
customer.name,
custacc.gl_no,
custacc.USERNAME,
customer.cust_type
FROM
custacc
LEFT JOIN
customer ON custacc.ac_no = customer.cust_no
INNER JOIN
(SELECT
MAX(DODSTART) LAST_UPDATE_DATE_TIME,
ac_no
FROM
custacc
GROUP BY
ac_no) s2 ON custacc.ac_no = s2.ac_no
AND custacc.DODSTART = s2.LAST_UPDATE_DATE_TIME
WHERE
custacc.od_limit != 0.00
The query doesn't return the expected result.
Try this(add columns that you need):
This is Oracle solution since you didn't mention it in your question:
SELECT ID,MAX(OD_LIMIT) OVER(PARTITION BY ID,EXTRACT(MONTH FROM DODSTART)) FROM CUSTACC;

Get dates missing from multiple date ranges

I have one table that stores when a customer support employee is in a particular location and for what date. Each separate date is its own record.
I have a second table that stores a range of dates that customers have asked for onsite support.
I need to extract a list of dates that a given location does NOT have any support representation. All I need is the location and the date(s). I don't care which employee in that location or which customer has requested the support.
So in the sample data below, I need to see as my query results:
+--------+------------+
| London | 04/01/2019 |
| London | 07/01/2019 |
| Paris | 05/01/2019 |
+--------+------------+
Table: Employee_Location
+----------+----------+------------+
| Employee | Location | Date |
+----------+----------+------------+
| 1111 | London | 01/01/2019 |
| 1111 | London | 02/01/2019 |
| 1111 | London | 03/01/2019 |
| 2222 | Paris | 01/01/2019 |
| 2222 | Paris | 02/01/2019 |
| 2222 | Paris | 03/01/2019 |
| 2222 | Paris | 04/01/2019 |
| 3333 | London | 05/01/2019 |
| 3333 | Paris | 06/01/2019 |
| 3333 | Paris | 07/01/2019 |
| 4444 | London | 06/01/2019 |
+----------+----------+------------+
Table: Customer_Request
+----------+----------+---------------+------------+
| Customer | Location | Request From | Request To |
+----------+----------+---------------+------------+
| AAAA | London | 01/01/2019 | 06/01/2019 |
| BBBB | Paris | 01/01/2019 | 06/01/2019 |
| CCCC | London | 05/01/2019 | 07/01/2019 |
+----------+----------+---------------+------------+
Here is my current code ...
select c.CALENDARDTM
from CALENDAR c, Employee_Location el
join Customer_Request cron el.location = cr.location
where c.CALENDARDTM NOT BETWEEN cr.RequestFrom and cr.RequestTo
and c.CALENDARDTM between '2019-01-01' AND '2019-01-07'
The key to solving this problem is to create a recordset that contains all dates between your nominated start and end dates.
There are a variety of methods you can use to do this, in the below example I have used a recursive CTE, for larger datasets you will need to tweak this slightly.
Once you have a list of all the dates, you combine it with a list of all locations, so you have all dates at all locations.?
Then you remove all records which match the records that already exists, in the example below a 'Not Exists' is used, but you can use a variety of approaches to get the desired outcome.
CREATE TABLE #Employee_Location (Employee int, [Location] varchar(100), [date] date)
INSERT INTO #Employee_Location (Employee, [Location], [Date])
VALUES (1111,'London','2019-01-01')
,(1111,'London','2019-01-02')
,(1111,'London','2019-01-03')
,(2222,'Paris','2019-01-01')
,(2222,'Paris','2019-01-02')
,(2222,'Paris','2019-01-03')
,(2222 ,'Paris','2019-01-04')
,(3333,'London','2019-01-05')
,(3333,'Paris','2019-01-06')
,(3333,'Paris','2019-01-07')
,(4444,'London','2019-01-06')
DECLARE #StartDate date = '2019-01-01'
DECLARE #EndDate date = '2019-01-07'
;WITH Dates AS (
SELECT #StartDate as d
UNION ALL
SELECT DateAdd(d, 1, d) as d
FROM Dates
WHERE d < #EndDate
)
,Locations AS (
SELECT DISTINCT [Location]
FROM #Employee_Location
)
,AllRecords AS (
SELECT d
,[Location]
FROM Dates
FULL OUTER JOIN Locations
ON 1=1
)
SELECT *
FROM AllRecords
WHERE NOT EXISTS (SELECT 1
FROM #Employee_Location e
WHERE e.[date] = Allrecords.d
AND e.[Location] = Allrecords.[Location])

Comparing SUM of values with different tables in SQL Server

I have two tables holding similar values, and I need to compare the two and find the differences between them:
SQL FIDDLE - http://sqlfiddle.com/#!6/7412e/9
Now you can see there is a difference between between the 2 tables for the figures in Jun-17.
AS you can see (as a total for everyone) table 1 has £75 for June but table 2 has £125 for june.
The result I'm looking for is when amounts are summed together and compared between tables on a monthly basis, if there is a difference in amount between the two tables I want it listed under 'Unknown'.
| MonthYear | Person | Amount | Month total
+-----------+--------+--------+--------------
| Jun-17 | Sam | 25 | 75(Table1)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 75(Table1)
| Jun-17 | Sam | 25 | 125(Table2)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 125(Table2)
| Jun-17 | | 50 | 125(Table2)
Now when there is a difference between the amount total over a month I want the difference to be classed as unknown
e.g
| MonthYear | Person | Amount | Month total
+-----------+--------+--------+--------------
| Jun-17 | Sam | 25 | 75(Table1)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 75(Table1)
| Jun-17 | Sam | 25 | 125(Table2)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 125(Table2)
| Jun-17 | Unknown| 50 | 125(Table2)
I understand that you could create a case when the person is null to display unknown but i need it to be specifically calculated on the difference between the 2 tables on a monthly calculation.
Does this make sense to anyone, its really hard to explain.
Generally, in any FROM clause a table name can be replaced with another SELECT as long as you give it a corelation name (t1 and t2 in this one):
SELECT t1.MonthYear, t1.AmountT1, t2.AmountT2, t1.amountT1 - isnull(t2.amountT2, 0) as Unknown'
from
( SELECT
MonthYear,
SUM(Amount) AS [AmountT1]
FROM
Invoice
GROUP BY MonthYear) t1
left outer join
( SELECT
MonthYear,
SUM(Amount) AS [AmountT2]
FROM
Invoice2
GROUP BY MonthYear) t2 on t2.MonthYear = t1.MonthYear

DBMS - Oracle | return multiple max values for multiple tables / relations

I need to return a list of customers who had ordered maximum number items. I have added the following and get some results but need to filter the query to display multiple maximum values.
DDL
CREATE TABLE Customer
(Cust_Num NUMBER(4) PRIMARY KEY,
Cust_LName VARCHAR2(10),
Cust_FName VARCHAR2(10),
Cust_Address VARCHAR2(20),
Cust_City VARCHAR2(12),
Cust_State VARCHAR2(2),
Cust_Zip VARCHAR2(5),
Cust_Referred NUMBER(4));
Create Table BookOrder
(BO_OrderNum NUMBER(4) PRIMARY KEY,
BO_CustNum NUMBER(4) REFERENCES Customer(Cust_Num),
BO_OrderDate DATE,
BO_ShipDate DATE,
BO_ShipStreet VARCHAR2(18),
BO_ShipCity VARCHAR2(15),
BO_ShipState VARCHAR2(2),
BO_ShipZip VARCHAR2(5));
CREATE TABLE BookOrderItem
(BOI_OrderNum NUMBER(4) NOT NULL REFERENCES BookOrder(BO_OrderNum),
BOI_ItemNum NUMBER(2) NOT NULL,
BOI_ISBN VARCHAR2(10) REFERENCES Book(Book_ISBN),
BOI_Qty NUMBER(3),
CONSTRAINT bookorderitem_pk PRIMARY KEY (BOI_OrderNum, BOI_ItemNum));
I have written the following DML:
SELECT C.CUST_LNAME, C.CUST_FNAME, BO.BO_CUSTNUM, BOI.BOI_ORDERNUM,
COUNT(BOI.BOI_ITEMNUM) AS Total_Items_Per_Order
FROM BookOrderItem BOI JOIN BookOrder BO ON BOI.BOI_OrderNum = BO.BO_OrderNum
JOIN Customer C ON C.Cust_Num = BO.BO_CustNum
GROUP BY C.Cust_LName, C.CUST_FName, BO.BO_CustNum, BOI.BOI_OrderNum
ORDER BY Total_Item_Per_Order DESC;
Which gives me the following results...
+------------+------------+------------+--------------+-----------------------+
| CUST_LNAME | CUST_FNAME | BO_CustNum | BOI_OrderNum | TOTAL_ITEMS_PER_ORDER |
+------------+------------+------------+--------------+-----------------------+
| NELSON | BECCA | 1017 | 1012 | 4 |
| GIANA | TAMMY | 1007 | 1007 | 4 |
| MORALES | BONITA | 1001 | 1003 | 3 |
| MORALES | BONITA | 1001 | 1018 | 2 |
| LUCAS | JAKE | 1010 | 1001 | 2 |
| GIRARD | CINDY | 1005 | 1009 | 2 |
| LEE | JASMINE | 1014 | 1013 | 1 |
| MONTIASA | GREG | 1018 | 1005 | 1 |
| MONTIASA | GREG | 1018 | 1019 | 1 |
| PIERSON | THOMAS | 1004 | 1008 | 1 |
| JONES | KENNETH | 1008 | 1020 | 1 |
| MCGOVERN | REESE | 1011 | 1002 | 1 |
| LUCAS | JAKE | 1010 | 1011 | 1 |
| FALAH | KENNETH | 1020 | 1015 | 1 |
| SMITH | JENNIFER | 1019 | 1010 | 1 |
| GIRARD | CINDY | 1005 | 1000 | 1 |
| SMITH | LEILA | 1003 | 1006 | 1 |
| GIANA | TAMMY | 1007 | 1014 | 1 |
| FALAH | KENNETH | 1020 | 1004 | 1 |
| SMITH | LEILA | 1003 | 1016 | 1 |
| SCHELL | STEVE | 1015 | 1017 | 1 |
+------------+------------+------------+--------------+-----------------------+
As per this screenshot...
To only keep the first row(s) you'd use FETCH FIRST n ROW(s) ONLY in Oracle 12c. To consider ties, you'd replace ONLY by WITH TIES:
...
ORDER BY Total_Item_Per_Order DESC
FETCH FIRST 1 ROW WITH TIES;
Please try the following...
SELECT Cust_LName,
Cust_FName,
Cust_Num AS Cust_Num,
BO_OrderNum AS Order_Num,
BOI_ItemNum AS Item_Num,
Max_Qty_Per_Order AS Max_Qty_Per_Order
FROM ( SELECT BOI_OrderNum AS Order_Num,
MAX( BOI_Qty ) AS Max_Qty_Per_Order
FROM BookOrderItem
GROUP BY BOI_OrderNum
) Max_Qty_Per_Order_Finder
JOIN BookOrderItem ON BookOrderItem.BOI_OrderNum = Max_Qty_Per_Order_Finder.Order_Num
AND BookOrderItem.BOI_Qty = Max_Qty_Per_Order_Finder.Max_Qty_Per_Order
JOIN BookOrder ON Max_Qty_Per_Order_Finder.Order_Num = BookOrder.BO_OrderNum
JOIN Customer Customer ON Customer.Cust_Num = BookOrder.BO_CustNum
ORDER BY Max_Qty_Per_Order DESC,
BO_OrderNum,
BOI_Item_Num;
This statement starts by creating a list of Order Numbers and the largest value of BOI_Qty associated with each.
The results of this subquery will be joined to BookOrderItem in such a way that only those records from BookOrderItem that have the largest value of BOI_Qty for their BookOrder will be returned. If more than one BookOrderItem for a particular BookOrder has the maximum value of BOI_Qty for that BookOrder, then each such record will be retained.
The resulting dataset is then joined to BookOrder so that the value of BO_CustNum for that BookOrder may be retrieved and be used to join the dataset to Customer, allowing for the Name of a Customer associated with each BookOrder to be retrieved.
The desired fields for each record in our final dataset are then retrieved and sorted.
Please note that I have included the field BOI_ItemNum in the selected fields as you asked for each record that has the maximum value of BOI_Qty to be returned. Without it such records would appear to be repeated. Including BOI_ItemNum will allow you to identify each record returned.
If you have any questions or comments, then please feel free to post a Comment accordingly.

Postgres: Adjust monthly calculations based on goals set

Below is my table:
practice_id | practice_name | practice_location | practice_monthly_revenue | practice_no_of_patients | date
-------------+-------------------+-------------------+--------------------------+-------------------------+---------------------
6 | Practice Clinic 1 | Location1 | 10000 | 8 | 2016-01-12 00:00:00
7 | Practice Clinic 1 | Location1 | 12000 | 10 | 2016-02-12 00:00:00
8 | Practice Clinic 1 | Location1 | 8000 | 4 | 2016-03-12 00:00:00
9 | Practice Clinic 1 | Location1 | 15000 | 10 | 2016-04-12 00:00:00
10 | Practice Clinic 1 | Location1 | 7000 | 3 | 2016-05-12 00:00:00
11 | Practice Clinic 2 | Location2 | 15000 | 12 | 2016-01-13 00:00:00
12 | Practice Clinic 2 | Location2 | 9000 | 8 | 2016-02-13 00:00:00
13 | Practice Clinic 2 | Location2 | 5000 | 2 | 2016-03-03 00:00:00
14 | Practice Clinic 2 | Location2 | 12000 | 9 | 2016-04-13 00:00:00
----------------------------------------------------------------------------------------------------------------------------------
I am firing below query to get monthly revenue vs monthly goal:-
select [date:month], SUM(practice_monthly_revenue) as Monthly_Revenue, 100000/12 as Goals
from practice_info
where practice_name IN ('Practice Clinic 1')
group by [date:month], practice_name
ORDER BY [date:month] ASC
Where "Monthly_Revenue" refers to exact revenue every month while Goal was the exact revenue expected to be generated.
Now I am having issue to write a sql query to adjust the goals next month if the goals aren't met.
E.g. if in March the revenue generated is below 8k which is the monthly goal then the remaining amount in goal should be adjusted in next months goal.
Will it be possible to achieve this with a sql query or I will have to write a sql procedure for it?
EDIT:- I forgot to add that the db belong to postgres.
Goals can be counted as
with recursive goals(mon, val, rev) as
(select min([pinf.date:month]) as mon /* Starting month */, 8000 as val /* Starting goal value */, pinf.practice_monthly_revenue as rev
from practice_info pinf
where pinf.practice_name IN ('Practice Clinic 1')
union all
select goals.mon + 1 as mon, 8000 + greatest(0, goals.val - goals.rev) as val, pinf.practice_monthly_revenue as rev
from practice_info pinf, goals
where goals.mon + 1 = [pinf.date:month]
and pinf.practice_name IN ('Practice Clinic 1')
)
select * from goals;
Just integrate it with your query to compare goals and revenues. It can be not exactly what you want, but I do believe you'll get the main point.