Same day, same customer but different branch transactions - sql-server

I have a table that contains Account Number, Transaction Date, Transaction Branch and amount.
I would like to generate a column that contains the information of:
if that specific customer, made a transaction from different branches on the same day.
An example of result is shown below:
AccountNumber Transaction_branch tran_Date Amount Different_Branch_Tran
11452 331 20/07/2020 500 no
11452 331 21/07/2020 500 no
5432 14 22/07/2020 500 no
5432 14 22/07/2020 500 no
11452 14 24/07/2020 500 yes
11452 420 24/07/2020 500 yes
11452 14 26/07/2020 500 no
I have a code that shows me if a customer made a same amount of transaction on the same day. however I couldn't figure it out how to modify or change this code to get the result I want.
select
a.*,
case when count(*) over(partition by trandate, accountnumber, amount) > 1 then 'Yes' else 'No' end SameAmountSameDay
from Tran_table a
where trandate> '20190701'

.....
case when
min(Transaction_branch) over(partition by AccountNumber, tran_Date, Amount)
=
max(Transaction_branch) over(partition by AccountNumber, tran_Date, Amount)
then 'No' else 'Yes'
end as SameAmountSameDayDifferentBranch
.........

One method is to use an EXISTS and a subquery, as you can't use DISTINCT in a windowed COUNT:
SELECT TT.AccountNumber,
TT.Tranasction_branch,
TT.tran_date,
TT.Amount,
CASE WHEN EXISTS(SELECT 1
FROM dbo.Tran_table sq
WHERE sq.AccountNumber = TT.AccountNumber
AND sq.Tran_Date = TT.Tran_Date
AND sq.Tranasction_branch != TT.Transaction_branch) THEN 'Yes' ELSE 'No' END AS Different_Branch_Tran
FROM dbo.Tran_table TT
WHERE TT.trandate > '20190701'; --This is called Tran_Date in your sample data, are these different columns?

Related

Write Query That Consider Date Interval

I have a table that contains Transactions of Customers.
I should Find Customers That had have at least 2 transaction with amount>20000 in Three consecutive days each month.
For example , Today is 2022/03/12 , I should Gather Data Of Transactions From 2022/02/13 To 2022/03/12, Then check These Data and See If a Customer had at least 2 Transaction With Amount>=20000 in Three consecutive days.
For Example, Consider Below Table:
Id
CustomerId
Transactiondate
Amount
1
1
2022-01-01
50000
2
2
2022_02_01
20000
3
3
2022_03_05
30000
4
3
2022_03_07
40000
5
2
2022_03_07
20000
6
4
2022_03_07
30000
7
4
2022_03_07
30000
The Out Put Should be : CustomerId =3 and CustomerId=4
I write query that Find Customer For Special day , but i don't know how to find these customers in one month with out using loop.
the query for special day is:
With cte (select customerid, amount, TransactionDate,Dateadd(day,-2,TransactionDate) as PrevDate
From Transaction
Where TransactionDate=2022-03-12)
Select CustomerId,Count(*)
From Cte
Where
TransactionDate>=Prevdate and TransactionDate<=TransactionDate
And Amount>=20000
Group By CustomerId
Having count(*)>=2
Hi there are many options how to achieve this.
I think that easies (from perfomance maybe not) is using LAG function:
WITH lagged_days AS (
SELECT
ISNULL(LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
,*
FROM Transaction
), valid_cust_base as (
SELECT
*
FROM lagged_days
WHERE DATEPART(MONTH, lagged) = DATEPART(MONTH, Transactiondate)
AND datediff(day, Transactiondate, lagged_dt) <= 3
AND Amount >= 20000
)
SELECT
CustomerID
FROM valid_cust_base
GROUP BY CustomerID
HAVING COUNT(*) >= 2
First I have created lagged TransactionDate over customer (I assume that id is incremental). Then I have Selected only transactions within one month, with amount >= 20000 and where date difference between transaction is less then 4 days. Then just select customers who had more than 1 transaction.
In LAG First value is always missing per Customer missing, but you still need to be able say: 1st and 2nd transaction are within 3 days. Thats why I am replacing first NULL value with LEAD. It doesn't matter if you use:
ISNULL(LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
OR
ISNULL(LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
The main goal is to have for each transaction closest TransactionDate.

Log Parser Studio: Counts of 500 errors and non-errors by month

Parsing w3c logs, I want to get the count of 500 errors and not for each month.
This gives the count of 500s per month:
SELECT TO_STRING(date, 'yyyy-MM') AS yearMonth, COUNT(*) AS HowMany
FROM '[LOGFILEPATH]'
WHERE cs-uri-stem LIKE '%pageIcareabout%'
AND sc-status = 500
GROUP BY yearMonth
Changing sc-status = 500 to sc-status <> 500 gives the count of not-500s.
However, I don't know how to show both 500s and not-500s, as separate columns for each month.
I ended up with this:
SELECT
TO_STRING(date, 'yyyy-MM') AS yearMonth
, SUM(500) AS 500s
, SUM(Not500) AS Not500s
USING
CASE sc-status WHEN 500 THEN 1 ELSE 0 END AS 500
, CASE sc-status WHEN 500 THEN 0 ELSE 1 END AS Not500
FROM '[LOGFILEPATH]'
WHERE cs-uri-stem LIKE '%pageIcareabout%'
GROUP BY yearMonth
Result is just what I wanted -- 3 columns, yearMonth, 500s, and Not500s, the last 2 being the count of their respective values for the month.
it looks like you want to use the CASE statement:
SELECT TO_STRING(date, 'yyyy-MM') AS yearMonth, MyStatus, COUNT(*) AS HowMany
USING CASE sc-status WHEN 500 THEN '500' ELSE 'Not500' END AS MyStatus
FROM ...
WHERE cs-uri-stem LIKE '%pageIcareabout%'
GROUP BY yearMonth, MyStatus

create date range report based on history table

We have been keeping track of some changes in a History Table like this:
ChangeID EmployeeID PropertyName OldValue NewValue ModifiedDate
100 10 EmploymentStart Not Set 1 2013-01-01
101 10 SalaryValue Not Set 55000 2013-01-01
102 10 SalaryValue 55000 61500 2013-03-20
103 10 SalaryEffectiveDate 2013-01-01 2013-04-01 2013-03-20
104 11 EmploymentStart Not Set 1 2013-01-21
105 11 SalaryValue Not Set 43000 2013-01-21
106 10 SalaryValue 61500 72500 2013-09-20
107 10 SalaryEffectiveDate 2013-04-01 2013-10-01 2013-09-20
Basically if an Employee's Salary changes, we log two rows in the history table. One row for the Salary value itself and the other row for the salary effective date. So these two have identical Modification Date/Time and are kind safe to assume that are always after each other in the database. We can also assume that Salary Value is always logged first (so it is one record before the corresponding effective date
Now we are looking into creating reports based on a given date range into a table like this:
Annual Salary Change Report (2013)
EmployeeID Date1 Date2 Salary
10 2013-01-01 2013-04-01 55000
10 2013-04-01 2013-10-01 61500
10 2013-10-01 2013-12-31 72500
11 2013-03-21 2013-12-31 43000
I have done something similar in the past by joining the table to itself but in those cases the effective date and the new value where in the same row. Now I have to create each row of the output table by looking into a few rows of the existing history table. Is there an straightforward way of doing this whitout using cursors?
Edit #1:
Im reading on this and apparently its doable using PIVOTs
Thank you very much in advance.
You can use self join to get the result you want. The trick is to create a cte and add two rows for each EmployeeID as follows (I call the history table ht):
with cte1 as
(
select EmployeeID, PropertyName, OldValue, NewValue, ModifiedDate
from ht
union all
select t1.EmployeeID,
(case when t1.PropertyName = "EmploymentStart" then "SalaryEffectiveDate" else t1.PropertyName end),
(case when t1.PropertyName = "EmploymentStart" then t1.ModifiedDate else t1.NewValue end),
(case when t1.PropertyName = "SalaryValue" then t1.NewValue
when t1.PropertyName = "SalaryEffectiveDate" then "2013-12-31"
when t1.PropertyName = "EmploymentStart" then "2013-12-31" end),
"2013-12-31"
from ht t1
where t1.ModifiedDate = (select max(t2.ModifiedDate) from ht t2 where t1.EmployeeID = t2.EmployeeID)
)
select t3.EmployeeID, t4.OldValue Date1, t4.NewValue Date2, t3.OldValue Salary
from cte1 t3
inner join cte1 t4 on t3.EmployeeID = t4.EmployeeID
and t3.ModifiedDate = t4.ModifiedDate
where t3.PropertyName = "SalaryValue"
and t4.PropertyName = "SalaryEffectiveDate"
order by t3.EmployeeID, Date1
I hope this helps.
It is a little over kill to use pivot since you only need two properties. Use GROUP BY can also achieve this:
;WITH cte_salary_history(EmployeeID,SalaryEffectiveDate,SalaryValue)
AS
(
SELECT EmployeeID,
MAX(CASE WHEN PropertyName='SalaryEffectiveDate' THEN NewValue ELSE NULL END) AS SalaryEffectiveDate,
MAX(CASE WHEN PropertyName='SalaryValue' THEN NewValue ELSE NULL END) AS SalaryValue
FROM yourtable
GROUP BY EmployeeID,ModifiedDate
)
SELECT EmployeeID,SalaryEffectiveDate,
LEAD(SalaryEffectiveDate,1,'9999-12-31') OVER(PARTITION BY EmployeeID ORDER BY SalaryEffectiveDate) AS SalaryEndDate,
SalaryValue
FROM cte_salary_history

Need Top N Row for Large Dataset. Query is taking a long time. How to optimize?

I have two tables (SalesforceTasks and SalesforceContacts) that I am using for a scoring system project. A simple SELECT statement with a ROW_NUMBER() calculation is taking a very long time to run and actually stops querying once it hits a certain number of rows. The query doesn't stop executing, but it stops returning data.
Here is the query in question. It is a very vanilla process, where I need to get the newest date in the SalesforceTasks table and link it to the contact ID in the SalesforceContacts table. The SalesforceTasks table has 2,091,946 rows and the SalesforceContacts table has 446,772 rows.
Here is the query in question:
SELECT SC.ID
,CASE
WHEN DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 360 AND 1500
THEN 15
WHEN DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 181 AND 360
THEN 10
WHEN DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 60 AND 180
THEN 5
ELSE 0
END AS Score
,ROW_NUMBER() OVER (PARTITION BY ST.ACCOUNTID ORDER BY ACTIVITYDATE) AS LastCall
FROM Salesforce.dbo.SalesforceTasks AS ST
JOIN Salesforce.dbo.SalesforceContacts AS SC
ON ST.ACCOUNTID = SC.ACCOUNTID
WHERE STATUS = 'Completed'
AND TYPE LIKE 'Call%'
What is the best plan of attack here? As stated, the query is taking a very, very long time to run. Is there a better way to get the newest date from the SalesforceTasks table?
You could try breaking the statement down in to a 2 step process.
First filter records into #temp table and get the datediff without the CASE:
SELECT SC.ID
,DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) AS ScoreDiff
,ROW_NUMBER() OVER (PARTITION BY ST.ACCOUNTID ORDER BY ACTIVITYDATE) AS LastCall
INTO #TEMP
FROM Salesforce.dbo.SalesforceTasks AS ST
JOIN Salesforce.dbo.SalesforceContacts AS SC
ON ST.ACCOUNTID = SC.ACCOUNTID
WHERE STATUS = 'Completed'
AND TYPE LIKE 'Call%'
AND DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 60 AND 1500
With the reduced dataset, you then perform the Scoring operation:
SELECT Id,
CASE ScoreDiff
WHEN BETWEEN 360 AND 1500
THEN 15
WHEN BETWEEN 181 AND 360
THEN 10
WHEN BETWEEN 60 AND 180
THEN 5
ELSE 0
END AS Score,
LastCall
FROM #temp
If purpose is just to get latest one then you can try this else need to find out other way
SELECT SC.ID,CASE
WHEN DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 360 AND 1500
THEN 15
WHEN DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 181 AND 360
THEN 10
WHEN DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 60 AND 180
THEN 5
ELSE 0
END AS Score,
SFC.ACTIVITYDATE
FROM Salesforce.dbo.SalesforceTasks AS ST
JOIN Salesforce.dbo.SalesforceContacts AS SC
CROSS APPLY
(
SELECT MAX(SFC.ID) AS SCID,MAX(SFC.ACTIVITYDATE) AS ACTIVITYDATE FROM Salesforce.dbo.SalesforceContacts SFC
WHERE SFC.ACCOUNTID=SC.ACCOUNTID
GROUP BY BY SFC.ACCOUNTID
HAVING MAX(SFC.ID)= SC.ID
)
ON ST.ACCOUNTID = SC.ACCOUNTID
WHERE STATUS = 'Completed'
AND TYPE LIKE 'Call%'
AND DATEDIFF(DD, ST.CREATEDDATE, GETDATE()) BETWEEN 60 AND 1500

Difference of two months expenses category wise in sql

I am trying to find the difference of expenses of previous and current month in sql.
I have a table like this
Date Amount Category
2/18/2015 100 Salary
2/12/2015 150 Rent
2/21/2015 200 Allowances
1/4/2015 200 Salary
1/17/2015 50 Rent
1/20/2015 100 Allowances
Now I want a result like this
Category CurrentMonthAmount PreviousMonthAmount Difference
Salary 100 200 100
Rent 150 50 100
Allowances 200 100 100
Try using conditional Aggregate
;WITH cte
AS (SELECT Category,
Max(CASE WHEN Month([date]) = Month(Getdate()) and year([date]) =year(getdate()) THEN amount END) CurrentMonthAmount,
Max(CASE WHEN Month([date]) = Month(Getdate()) - 1 and year([date]) =year(getdate()) THEN amount END) PreviousMonthAmount
FROM Yourtable
GROUP BY Category)
SELECT Category,
CurrentMonthAmount,
PreviousMonthAmount,
[Difference]=Abs(CurrentMonthAmount - PreviousMonthAmount)
FROM cte
SQLFIDDLE DEMO
Are you trying to do the computations within your SQL only or via some scripts like PHP.? Furthermore, can you state if you are choosing specific records for this operation (specific rows i mean). Give some more clarification

Resources