SQL First and Last Transaction Report - sql-server

I have a table in SQL, that looks a little similar to the table below:
[enter image description here]
My goal is to generate a first and Last Transaction report.
I want to know when did customer X make their first purchase and what is the date of their most recent purchase.
I would like to group my results by Store and add all the transaction if they happen on the same day.
For instance, if John do made 2 expenses at walmart on Jan 15th and that's their most recent transaction, I would like those two expenses to be Summed in my report.
Here is the final result I'd expect from a table like on the example above:
[enter image description here]
With what I have tried so far,
I am only getting 1 value back
The SQL looks a little similar to
Select
SN
, SID
, CustomerName
, BankAccount
, Min(TransDate)
, Max(TransDate)
, price
, store
From transaction
GROUp by
SN
, SID
, CustomerName
, BankAccount
, Min(TransDate)
, Max(TransDate)
, price
, store
I know I have to use some types of nested query to get the result(maybe) but I have been unsuccessful.

I would try and pull out the customer info you need to filter out the rest of the data. I would start with a CTE to get the MIN and MAX dates for each customer. I would then JOIN that back up to the original table and just get the records for the Customer that are on that MAX date.
I would assume you have something that is more Unique then the customer name, and if so I would use that instead. But here is what I came up with given the data you provided:
CREATE TABLE #tmp(SerialNumber int, SearialID int,CustomerName varchar(100), BankAccount int,
TranDate date, Price decimal(10,2),TracerID int,Store varchar(20))
INSERT INTO #tmp VALUES
(2,2,'Peter Smith',14564,'1/1/2021',10,756,'Kroger'),
(1,1,'John Do',12345,'1/1/2021',10,156,'Walmart'),
(1,1,'John Do',12345,'1/15/2021',5,148,'Walmart'),
(1,1,'John Do',12345,'1/15/2021',15,148,'Walmart'),
(2,2,'Peter Smith',14564,'1/12/2021',12,756,'Kroger')
;WITH CTE AS
(
SELECT Min(TranDate) FirstDate, Max(TranDate) LastDate, CustomerName
FROM #tmp
GROUP BY CustomerName
)
SELECT T.SerialNumber,T.SearialID,T.CustomerName,t.BankAccount,C.FirstDate FirstTrans, C.LastDate,SUM(t.Price) Price,T.Store
FROM #tmp T
INNER JOIN CTE C on t.CustomerName = c.CustomerName and t.TranDate = c.LastDate
GROUP BY T.SerialNumber,T.SearialID,T.CustomerName,t.BankAccount,C.FirstDate,C.LastDate,T.Store

Related

SQL to identify initial dates for a product that changes from active to cancelled status

I have a table that records the following items:
product_id
product_status
date
Products can exist in the following product statuses: pending, active, or canceled. Only one status can exist per date per product code. A status and product code is inserted for each and every day a product exists.
Utilizing SQL I'd like to be able to identify the initial cancellation dates for a product that cancels more than once in a given time frame.
i.e. if a product is active for 3 days and then cancels for 3 days and then is active again for 3 days and then cancels again for another 3 days.
I'd like to be able to identify day 1 of the 2 cancellation periods.
Thought I'd get the crystal ball out for this one. This sounds like a Gaps and Islands question. There's plenty of answers on how to do this on the internet, however, this might be what you're after:
CREATE TABLE #Sample (product_id int,
product_status varchar(10),
[date] date); --blargh
INSERT INTO #Sample
VALUES (1,'active', '20170101'),
(1,'active', '20170102'),
(1,'active', '20170103'),
(1,'cancelled', '20170104'),
(1,'cancelled', '20170105'),
(1,'cancelled', '20170106'),
(1,'active', '20170107'),
(1,'pending', '20170108'),
(1,'active', '20170109'),
(1,'cancelled', '20170110'),
(2,'pending', '20170101'),
(2,'active', '20170102'),
(2,'cancelled', '20170103'),
(2,'cancelled', '20170104');
GO
SELECT *
FROM #Sample;
WITH Groups AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY product_id
ORDER BY [date]) -
ROW_NUMBER() OVER (PARTITION BY product_id, product_status
ORDER BY [date]) AS Grp
FROM #Sample)
SELECT product_id, MIN([date]) AS cancellation_start
FROM Groups
WHERE product_status = 'cancelled'
GROUP BY Grp, product_id
ORDER BY product_id, cancellation_start;
GO
DROP TABLE #Sample;
If not, then see Patrick Artnet's comment.

SQL Server Select query returning records twice in a table

I am using the following query to get the top 10 companies from a table:
Select Top 10 CompanyName
From CompanyMaster
Where LiveProductFlag = 1
Order By Display_Priority asc
It is returning records like this.
CompanyName
------------
First Company
Second Company
First Company
Second COmpany
Third Company
Third Company
Fourth Company
Fourth Company
Fifth Company
Fifth Company
I checked records and I don't have duplicate records. Select Distinct doesn't work. Tried all possible solutions after googling without any success.
Thanks.
You can run a simple count on your group field query as follows to doublecheck your assumption.
Select
CompanyName,
DuplicateCount=COUNT(*)
From
CompanyMaster
Where
LiveProductFlag = 1
GROUP BY
CompanyName
HAVING
COUNT(*) > 1
ORDER BY
COUNT(*) DESC

Sum field(s) from one table in another table, summing from 3 different tables

I have an Access database with customer IDs. Each customer can have multiple orders and each order can be of a different type. I have three separate tables (Online, In-store, Payment Plan) for each order type with various amounts from each order, all are related to a customer ID. In one of the tables, there are two types of order types that amounts must be maintained separately withing the same table. I want to sum each order type in another table called Totals. I can successfully create a query to get the sums for each type based on the customer ID but I am not sure how to pull those values in my Totals table. The scenario below is repeated for multiple customers and each type is its own table---the payment plans are in a table together. I have historical data so I am limited to how I can manipulate as far as merging fields and what not.
Customer ID#: 1
Order Type: Online
Online Amount: $20.00
Order Type: Online
Online Amount: $40.00
Sum of Online Amount: $60.00
Order Type: In-store
Online Amount: $35.00
Order Type: In-store
Online Amount: $60.00
Sum of In-Store Amount: $95.00
Order Type: Payment Plan
Payment Plan 1 Amount: $30.00
Payment Plan 1 Amount: $23.00
Sum of Payment Plan 1 Amount: $53.00
Order Type: Payment Plan 2
Payment Plan 2 Amount: $35.00
Payment Plan 2 Amount: $30.00
Sum of Payment Plan 2 Amount: $65.00
In my Totals table I have a field for each type that sums the amount spent by each customer ID and then a field where all of their order types are summed into one overall total field.
I am learning as I go so any help/example is appreciated. Thank you.
Having separate tables for your different order types doesn't help. For a database it would be better to have a single table for all sales with a sale_type field.
You don't describe exactly what your tables look like, so I've had to make a couple of assumptions. If your tables contain an OrderType field then you can create a Union query to join all your sales together:
SELECT CustomerID
, OrderType
, Amount
FROM Online
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [In-Store]
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [Payment Plan]
If you don't have an OrderType you can hard-code the values into the query:
SELECT CustomerID
, "Online" AS OrderType
, Amount
FROM Online
UNION ALL SELECT CustomerID
, "In-Store"
, Amount
FROM [In-Store]
UNION ALL SELECT CustomerID
, "Payment Plan"
, Amount
FROM [Payment Plan]
Note - The field name is declared for the OrderType in the first Select block. You could do it in each block, but Access only looks at the first.
Like all queries, the results come in table form and can be treated as such. So now we need to list the CustomerName (I'm assuming you have a Customers table), the OrderType and the sum of the amount for that Customer & OrderType.
SELECT CustomerName
, OrderType
, SUM(Amount)
FROM Customers INNER JOIN
(
SELECT CustomerID
, OrderType
, Amount
FROM Online
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [In-Store]
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [Payment Plan]
) T1 ON Customers.CustomerID = T1.CustomerID
GROUP BY CustomerName
, OrderType
All sales in your three tables will have a customer within the customers table so we can use an INNER JOIN to return only records where the value appears in both tables (Customers table & result of query table).
The UNION QUERY is wrapped in brackets and given the name T1and joined to the Customers table on the CustomerID field.
We group all fields that aren't part of an aggregate function, so group on CustomerName and OrderType and sum the Amount field.
This is all you really need to do - let the query run each time you want the totals to get the most up to date values. There's shouldn't be a need to push the results to a Totals table as that will be out of date as soon as you make a new sale (or someone returns something).
If you really want to INSERT these figures into a Total table just add a first line to the SQL:
INSERT INTO Total (CustomerName, OrderType, Amount)
Here is a dirty workaround, though I think there might be a more direct solution to it.
You could create an output table (I broke it down to ID, Online, InStore and Total) and use DSum functions within an UPDATE query.
UPDATE tbl_Totals SET
Total_InStore = DSum("Amount", "tbl_InStore", "Customer_ID = " & Customer_ID),
Total_Online = DSum("Amount", "tbl_Online", "Customer_ID = " & Customer_ID),
Total = DSum("Amount", "tbl_InStore", "Customer_ID = " & Customer_ID) + DSum("Amount", "tbl_Online", "Customer_ID = " & Customer_ID)

Problèm with SQL select grouping

I have a small problem with a SQL Server query.
I have an issue with my view of several base tables with duplicate values, so far no problem, these duplicates are logical. By unfortunately I do not get the desired end result, I could do it by programming the front end of my application but I would prefer to do the work on the server.
I will explain the principle:
I have 30 companies which each have an employee table.
My view is a union of the 30 employee tables.
Each employee has a unique serial number, the number is the same across tables, so an employee named "John Doe" with an ID number 'S0000021' can be hired in Company A then transferred to company Q without any problems, it will retain the serial number 'S0000021'.
The difference between the data from the Employee tables A and Q will be in this example the start (hire) and release (transfer) dates entered for Company A and just the start date for company Q so the view will have 2 lines for "John Doe".
12 common fields are the following:
Serial Number (Identical in every employee table)
Social Security Number (Same in every employee table)
Start/Hire Date
Release/Transfer date (empty/null if the employee is current)
Name (Can change across companies if the person divorces)
First name
Maiden name
Last Name
Gender
Final Released
Company Code
The problem seems simple that I would not appear that the latest information of the employee, except with a group by, if it has changed name or release date, it will be displayed twice.
I tried the following different ways but they don't return what I want
I returned results both ways but I always see duplicates because my dates within companies are never identical, and their name may change.
Sorry for this Google translation.
1 --
select
vue.matricule,
vue.numsecu,
vue.name,
vue.lastname,
vue.maidenname,
vue.secondname,
vue.genre,
vue.released,
vue.companycode
from
vue
group by
vue.matricule,
vue.numsecu,
vue.name,
vue.lastname,
vue.maidenname,
vue.secondname,
vue.genre,
vue.released,
vue.companycode
2---
select
distinct(vue.matricule),
vue.numsecu,
vue.name,
vue.lastname,
vue.maidenname,
vue.secondname,
vue.genre,
vue.released,
vue.companycode
from
vue
I assumed the following:
there is a view (vue) that already gathers all data from each of the 30 companies
you are just looking for the latest record for each employee
If you need to also see a record for each name change we can change this.
--set up test data
declare #vue table (
matricule varchar(20),
numsecu varchar(20),
name varchar(20),
lastname varchar(20),
maidenname varchar(20),
secondname varchar(20),
genre varchar(20),
start datetime,
released datetime,
companycode varchar(20));
insert #vue values
('S0000021','123456789','John', 'Doe',null,null,'M','2015-01-01','2015-12-31','A'),
('S0000021','123456789','Johnny', 'Doe',null,null,'M','2016-01-01',null,'Q'), --new company, name change, currently employed
('S0000022','123456780','Jane', 'Doe',null,null,'M','2015-01-01','2015-12-31','A'),
('S0000022','123456780','Jane', 'Doe',null,null,'M','2016-01-01','2016-02-01','Q'); --new company, name change, terminated
select * from #vue order by matricule, start;
--get latest record for each employee
select *
from (--add row numbering
select *, row_number() over (partition by matricule order by start desc) row_num
from #vue
) vue2
where vue2.row_num = 1;

How Can i Create a View or table out of two tables so that their rows are not merged?

I have two views that i want tho merge them into one view so that their records are not merge into one record! i mean suppose I have these tables :
Table one(suppose this is a sell table were our customer sold something!)
Date Description Fee Number Money
12/2/2012 something 10$ 20 200$
10/3/2012 somethingelse 20$ 30 600$
Table Two (suppose this is the table where our customer got money!)
Date Description Money
02/8/2012 someinfo 5000$
12/1/2012 stuff 3100$
And the resulting Table or view would be(based on the descending order on date) :
Date Description Fee Number Money
02/8/2012 someinfo 0 0 5000$
10/3/2012 somethingelse 20$ 30 600$
12/2/2012 something 10$ 20 200$
12/1/2012 stuff 0 0 3100$
How can I achieve this form? These two tables are separate ,but each has a unique personal ID which represents the salesmen account. ( so basically this means that these information belong to one person only.and our customer wants a report that gives him this specific view only!)
I tried using UNION on these two tables , but the rows where merged!!
If i use Joins there would only be a row where the two tables row are merged together .So I am stuck here and dont know what to do now .
I think you need UNION ALL not just UNION.
select Date, Description, Fee, Number, Money
from table1
UNION ALL
select Date, Description, 0 Fee, 0 Number, Money
from table2
order by Date
Try somthing like
CREATE VIEW vMyView
AS
SELECT [Date], [Description], [Fee], [Number], [Money]
FROM v1
UNION ALL
SELECT [Date], [Description], 0 AS [Fee], 0 AS [Number], [Money]
FROM v2
I think this should do it.
CREATE VIEW new_view AS
SELECT * FROM table_one
UNION ALL
SELECT *, 0 as Fee, 0 as Number FROM table_two;

Resources