SQL Query For Customers Not Used For Last 3 Years - sql

I THINK I'm having some trouble.
I'm trying to query 2 tables for customers that haven't been used on the table for the last 3 Years. The data consists of data ranging for 7+ years, so customers are used multiple times.
I think the issue with my current query: It's finding data of customers not used in the last 3 years... but it's not accounting for if there is also data of the customer within the last 3 years as well.
Can someone possibly help me? I'm guessing the answer is to use only the data of the customer with the latest date and ignore previous data.
SELECT DISTINCT
tbl_Customer.CustomerID
, tbl_Customer.CustomerName
, Table1.ImportDate
, Table2.ImportDate
FROM
tbl_Customer
LEFT JOIN
Table1 ON tbl_Customer.CustomerName = Table1.CustomerName
LEFT JOIN
Table2 ON tbl_Customer.CustomerName = Table2.CustomerName
WHERE
(((DateAdd("yyyy", 3, [Table2].[ImportDate])) < Now())
AND
((DateAdd("yyyy", 3, [Table1].[ImportDate])) < Now()))
ORDER BY
Table1.ImportDate DESC,
Table2.ImportDate DESC;

The core problem with the initial query is that, for no imports (which will happen for "no order" customers) the condition
DateAdd("yyyy", 3, ImportDate) < Now()
--> DateAdd("yyyy", 3, NULL) < Now()
--> NULL < Now()
--> NULL (or not true)
is not true. A simple fix is to add a guard
([Table1].[ImportDate] IS NULL
OR DateAdd("yyyy", 3, [Table1].[ImportDate]) < Now())
around such expressions or to coalesce the NULL value before using it.
The ordering will also be wrong, as that means order by one value and then the other, not "by the greater of both" values. Compare with
ORDER BY
IIF(Table1.ImportDate > Table2.ImportDate, Table1.ImportDate, Table2.ImportDate)
However, I would use a LEFT JOIN on customers/orders, GROUP BY with a MAX on the order dates. Then you can use that result (as a derived subquery) to complete the query asked fairly trivially.
SELECT
c.CustomerID
, MAX(o.ImportDate) as lastImport
FROM tbl_Customer as c
-- The UNION is to simply "normalize" to a single table.
-- (Also, shouldn't the join be on a customer "ID"?)
LEFT JOIN (
SELECT CustomerName, ImportDate from Table1
UNION
SELECT CustomerName, ImportDate from Table2) as o
ON c.CustomerName = o.CustomerName
GROUP BY c.CustomerID
Then,
SELECT s.CustomerID
FROM (thatSubQuery) as s
WHERE
-- no orders
s.lastImport IS NULL
-- only old orders
OR DateAdd("yyyy", 3, s.lastImport) < Now()
ORDER BY s.lastImport
(YMMV with MS Access, this will work in a "real" database ;-)

SELECT DISTINCT
tbl_Customer.CustomerID,
tbl_Customer.CustomerName,
Table1.ImportDate,
Table2.ImportDate
FROM (tbl_Customer
LEFT JOIN Table1
ON tbl_Customer.CustomerName = Table1.CustomerName)
LEFT JOIN Table2
ON tbl_Customer.CustomerName = Table2.CustomerName
WHERE DateAdd("yyyy",3,[Table2].[ImportDate]) < Now()
AND DateAdd("yyyy",3,[Table1].[ImportDate]) < Now()
AND tbl_Customer.CustomerID NOT IN (
SELECT DISTINCT
tbl_Customer.CustomerID,
FROM (tbl_Customer
LEFT JOIN Table1
ON tbl_Customer.CustomerName = Table1.CustomerName)
LEFT JOIN Table2
ON tbl_Customer.CustomerName = Table2.CustomerName
WHERE DateAdd("yyyy",3,[Table2].[ImportDate]) >= Now()
AND DateAdd("yyyy",3,[Table1].[ImportDate]) >= Now()
)
ORDER BY Table1.ImportDate DESC , Table2.ImportDate DESC;

Based on what I can infer from your query about your data structure, I think you want something like this:
DECLARE #CutOff DateTime
SET #CutOff = DATEADD(y, -3 GETDATE())
SELECT tbl_Customer.CustomerID, tbl_Customer.CustomerName
WHERE (CustomerName IN
(SELECT CustomerName FROM Table1 WHERE ImportDate < #CutOff))
OR
(CustomerName IN
(SELECT CustomerName FROM Table2 WHERE ImportDate < #CutOff)))
AND CustomerName NOT IN
(SELECT CustomerName FROM Table1 WHERE ImportDate > #CutOff)
AND CustomerName NOT IN
(SELECT CustomerName FROM Table2 WHERE ImportDate > #CutOff)

Related

Take the last in the query

I have a query like this:
Select *
From Table1 as ad
inner join Table2 as u
on u.employee_ident=ad.employee_ident
inner join Table3 as t
On u.employee_ident=t.employee_ident and u.hire_date=t.hire_date
where DATEDIFF(day,t.term_date,GETDATE() )>=60 AND u.status in ('nohire','1') and u.company_group_abbr_name='ABC'
order by
t.term_date asc
Table3 for the same user has more than one term_date. I want that when I run this query in the moment that the compare will be done in DATEDIFF(day,t.term_date,GETDATE() )>=60 in the part of t.term_date it will take the last one. Actually when I run it it makes the compare with the first one that it finds.
So from the dates 2018, 2020, and 2022 it compares with 2018 and I want it to make the compare with 2022 which is the most recent one. How can I do this?
Try something like this:
WITH T3Latest (
employee_ident,
hire_date,
term_date,
term_rank
)
AS (
SELECT employee_ident,
hire_date,
term_date,
RANK() OVER (
PARTITION BY employee_ident ORDER BY term_date DESC
) term_rank
FROM Table3
)
SELECT *
FROM Table1 AS ad
INNER JOIN Table2 AS u ON u.employee_ident = ad.employee_ident
INNER JOIN T3Latest AS t ON u.employee_ident = t.employee_ident
AND u.hire_date = t.hire_date
WHERE t.term_rank = 1
AND DATEDIFF(day, t.term_date, GETDATE()) >= 60
AND u.STATUS IN (
'nohire',
'1'
)
AND u.company_group_abbr_name = 'ABC'
ORDER BY t.term_date ASC;

SQL Query 1 have count Function and to get data from another SQL Query 2 where memberid is same

My First Query is
SELECT
memberid,
count(*) count
From
dbo.Transactions
group by
dbo.Transactions.MemberID
having
count(memberid) > 1
My query 2 is
SELECT
transactionlog.id,
transactionlog.transactionid,
transactionlog.transactionamount,
transactionlog.transactiondate,
transactions.MemberID,
GymMember.FirstName,
from
dbo.GymMember
inner join Transactions on
GymMember.MemberID = Transactions.MemberId
inner join TransactionLog on
Transactions.Id = TransactionLog.TransactionId
Results of Query 2 are givne in below image
Now i want to have data where query 1 member id and query 2 member id are same
Do you mean find data where the MemberID from the second query exists in the first query? If so please see query below.
SELECT
transactionlog.id,
transactionlog.transactionid,
transactionlog.transactionamount,
transactionlog.transactiondate,
transactions.MemberID,
GymMember.FirstName,
from
dbo.GymMember
inner join Transactions on
GymMember.MemberID = Transactions.MemberId
inner join TransactionLog on
Transactions.Id = TransactionLog.TransactionId
WHERE
Transactions.MemberId IN
(SELECT
memberid
FROM
dbo.Transactions
group by
dbo.Transactions.MemberID
having
count(memberid) > 1))
I was working on it from more than 24 hours and after try and trial i found the solution but Senior can recommend a more proper way to do this My Solution is
SELECT* FROM( SELECT* FROM
(select transactionlog.id, transactionlog.transactionid, transactionlog.transactionamount, transactionlog.transactiondate, transactions.MemberID, GymMember.FirstName, GymMember.CellNumber from dbo.GymMember
inner join Transactions on GymMember.MemberID = Transactions.MemberId
inner join TransactionLog on Transactions.Id = TransactionLog.TransactionId) as MYTABLE where Exists
(select dbo.transactions.memberid,count(dbo.transactions.memberid) From dbo.Transactions Where mytable.MemberID = dbo.Transactions.MemberID group by dbo.Transactions.MemberID having count(dbo.Transactions.MemberID) > 1)) AS mynewtable where convert(datetime,TransactionDate,103) between '2022-09-30 00:00:00' and '2022-10-01 00:00:00'

Insert data in ssrs table in the query

I would like to insert some data in the ssrs table.
I would like to show it like this here:
How can I add these data in my query in SSRS. I have no possibility to change something in the database.
| P1|P2 |P3 |P4 |P5 |P6 |P7 |P8
Group A|84%|87%|81%|81%|79%|96%|86%|88%
Group B|66%|22%|79%|64%|53%|94%|5% |23%
The Problem is:
Last week on wednesday the database did not recorded the data from Group A and Group B. And I have no possibility to correct/add the missing data in the database. And thats why I would like to add these missed data in my query and show it in the report.
My query:
SELECT *
FROM (
Select
intervaldate as Datum
,tsystem.Name as Name
,team as group
,SUM(GoodUnits) As Goods
,SUM(TheoreticalUnits) As Units
from tCount inner join tsystem ON tCount.systemid = tsystem.id
where IntervalDate >= #StartDateTime AND IntervalDate <= #EndDateTime
group by intervaldate
) c
inner join
(
SELECT
sh.Date as Datum,
sc.Name as Name
FROM tHistory sh
INNER JOIN tSchedule sc ON (sc.ID = sh.ScheduleID)
WHERE Scheduled != 0
) p ON p.Name = c.Name
When I realized that the data was not recorded I did written down the data on paper.
To add manual data to your posted query, you can use UNION ALL and VALUES like so:
First make sure you get your 'additional data' correct on its own. Try this example:
SELECT Datum,Name,[Group],Goods,Units
FROM (
VALUES
(CAST('2015-01-01' AS DATE),'AName','A',10.32,20.76),
(CAST('2015-01-01' AS DATE),'AName','B',12.72,16.15)
) AS ExtraData(Datum,Name,[Group],Goods,Units);
I am making many assumptions here as you have not provided enough info in your question.
Anyway if that is correct, then you simply attach it to your original data with UNION ALL
SELECT Datum,Name,[Group],Goods,Units
FROM (
Select
intervaldate as Datum
,tsystem.Name as Name
,team as [Group]
,SUM(GoodUnits) As Goods
,SUM(TheoreticalUnits) As Units
from tCount inner join tsystem ON tCount.systemid = tsystem.id
where IntervalDate >= #StartDateTime AND IntervalDate <= #EndDateTime
group by intervaldate
) c
inner join
(
SELECT
sh.Date as Datum,
sc.Name as Name
FROM tHistory sh
INNER JOIN tSchedule sc ON (sc.ID = sh.ScheduleID)
WHERE Scheduled != 0
) p ON p.Name = c.Name
/* Original query ends. Now add more data */
UNION ALL
SELECT Datum,Name,[Group],Goods,Units
FROM (
VALUES
(CAST('2015-01-01' AS DATE),'AName','A',10.32,20.76),
(CAST('2015-01-01' AS DATE),'AName','B',12.72,16.15)
) AS ExtraData(Datum,Name,[Group],Goods,Units);

Display Y/N column if record found in detail table

I'm trying to create a query so that I can have a column show Y/N if a particular item was ordered for a group of orders. The item I'm looking for would be OLI.id = '538'.
So my results would be:
Order#, Customer#, FreightPaid
12345, 00112233, Y
12346, 00112233, N
I cannot figure out if I need to use a subquery or the where exists function ?
Here's my current query:
SELECT distinct
OrderID,
Accountuid as Customerno
FROM [SMILEWEB_live].[dbo].[OrderLog] OL
inner join Orderlog_item OLI on OLI.orderlogkey = OL.[key]
inner join Account A on A.uid = OL.Accountuid
where A.GroupId = 'X9955'
and OL.CreateDate >= GETDATE() - 60
I would suggest an exists clause instead of a join:
select ol.OrderID, ol.Accountuid as Customerno,
(case when exists (select 1
from Orderlog_item OLI join
Account A
on A.uid = OL.Accountuid
where OLI.orderlogkey = OL.[key] and A.GroupId = 'X9955'
)
then 1 else 0
end) as flag
from [SMILEWEB_live].[dbo].[OrderLog] OL
where OL.CreateDate >= GETDATE() - 60;
This prevents a couple of problems. First, duplicate rows which are caused when there are multiple matching rows (and select distinct add unnecessary overhead). Second, missing rows, which happen when you use inner join instead of an outer join.

How to determine two different aggregate dates on employee attendance data?

I Need help to implement employee attendance sheet. Presently am having employee attendance i.e
Query:
SELECT c.First_name + c.Middle_name + c.last_name AS employeename,
b.Device_Person_id,a.Dept_Id,Date1,
CASE WHEN b.Device_Person_id IS NOT NULL
THEN 'P'
ELSE 'A' END AS status
FROM Emp_setting a
LEFT OUTER JOIN (SELECT Device_Person_id, MAX(logDateTime) AS Date1
FROM tempDeviceLogs
GROUP BY Device_Person_id) b
ON a.personal_id = b.Device_Person_id
LEFT OUTER JOIN persons_profile c
ON c.pesonal_id=a.personal_id
Result:
employeename Device_person_id dept_id date1 status
MEHABOOB NULL 4 NULL A
UDAY NULL 26 NULL A
SHANKRAYYA NULL 10 NULL A
BASAVARAJ NULL 24 NULL A
BHIMAPPA 5 10 2014-05-23 14:14:00.000 P
i.e. Employeename BHIMAPPA is present on 2014-05-23.
NOW I want the list of employees who is present on 2014-05-23.
Please help?
Assuming that logDateTime indicates the presence of the employee, and given that the current derived table returns the MAX() of this field (presumably the last time the employee was detected) you would need another join to the tempDeviceLogs table to do the filtering. You could do the filtering at the same time with an INNER JOIN, viz:
...
INNER JOIN (SELECT Device_Person_id
FROM tempDeviceLogs
WHERE logDateTime >= '2014-05-23' and logDateTime < '2014-05-24') x
ON x.Device_Person_id = a.personal_id
Edit
Given that you want to SELECT the date as well, I'm assuming you want to parameterize it / use it for a range. And making yet another assumption about your SqlServer version being >= 2008, cast the DateTime to a Date and group by it:
SELECT c.First_name + c.Middle_name + c.last_name AS employeename,
b.Device_Person_id,a.Dept_Id, Date1 as DateTimeLastSeen,
x.logDate As DatePresent,
CASE WHEN b.Device_Person_id IS NOT NULL THEN 'P' ELSE 'A' END AS status
FROM Emp_setting a
LEFT OUTER JOIN (SELECT Device_Person_id, MAX(logDateTime) AS Date1
FROM tempDeviceLogs
GROUP BY Device_Person_id) b
ON a.personal_id = b.Device_Person_id
LEFT OUTER JOIN persons_profile c
ON c.pesonal_id=a.personal_id
INNER JOIN (SELECT Device_Person_id, CAST(logDateTime AS DATE) as logDate
FROM tempDeviceLogs
GROUP BY Device_Person_id, CAST(logDateTime AS DATE)) x
ON x.Device_Person_id = a.personal_id
WHERE
logDate BETWEEN '2014-05-01' AND '2014-05-23';
This could also be done with a DISTINCT. If you have an earlier version of SqlServer, use a hack like this to obtain the date part of a DateTime (in the select + group)
Create a variable to hold the date which you are looking for.
DECLARE #cutOffDate DATE
SET #cutOffDate = '23-05-2014'
Then add to the end of your statement
Where Date1 = #cutOffDate