I am new to SQL, I am trying to query from a ledger table
I have two Queries that I need to join into one table
1st Query:
SELECT *
FROM TABLE 1
WHERE DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 3
AND [ITEMTYPE] = 'F-C'
AND ([Description] NOT LIKE '%REFILE%'
AND [Description] NOT LIKE '%CROSSOVER%')
AND ([UserNAME] LIKE '%USER1%'
OR [UserNAME] LIKE '%user2%'
OR [UserNAME] LIKE '%user3%')
2nd Query:
SELECT [ENCID], SUM([Trans]) AS Total_Charges
FROM Table 1
WHERE DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 3
AND [ITEMTYPE] IN ('C')
GROUP BY [ENCID];
I need to Left join the 2nd Query to the 1st Query on ENCID
THanks.
Well, you just join it. Nothing special about it, except that you have to remember to give an alias e.g. Totals
I have also changed your DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 3 to [Transaction Date] >= DATEADD(MONTH, -3, GETDATE()), to allow SQL Server to use indexes on [Transaction Date] column, if you have any.
Also leading wild card text searches e.g. [UserNAME] LIKE '%user2%' are slow, avoid them if you can: https://sqlperformance.com/2017/02/sql-indexes/seek-leading-wildcard-sql-server
SELECT *
FROM TABLE 1 AS a
LEFT JOIN
( SELECT [ENCID], SUM([Trans]) AS Total_Charges
FROM Table 1
WHERE [Transaction Date] >= DATEADD(MONTH, -3, GETDATE())
AND [ITEMTYPE] IN ('C')
GROUP BY [ENCID] ) AS Totals ON Totals.[ENCID] = a.[ENCID]
WHERE
[Transaction Date] >= DATEADD(MONTH, -3, GETDATE())
AND [ITEMTYPE] = 'F-C'
AND ([Description] NOT LIKE '%REFILE%'
AND [Description] NOT LIKE '%CROSSOVER%')
AND ([UserNAME] LIKE '%USER1%'
OR [UserNAME] LIKE '%user2%'
OR [UserNAME] LIKE '%user3%')
When you introduce any joins (to tables or subqueries) it is vital that you refer to columns from those sources by aliases.
SELECT t1.*
FROM TABLE_1 t1
LEFT JOIN (
SELECT [ENCID], SUM([Trans]) AS Total_Charges
FROM Table_1
WHERE [Transaction Date] >= DATEADD(month,-3,GETDATE())
AND [ITEMTYPE] IN ('C')
GROUP BY [ENCID]
) sq ON t1.[ENCID] = sq.[ENCID]
WHERE t1.[Transaction Date] >= DATEADD(month,-3,GETDATE())
AND t1.[ITEMTYPE] = 'F-C'
AND (t1.[Description] NOT LIKE '%REFILE%'
AND t1.[Description] NOT LIKE '%CROSSOVER%')
AND (t1.[UserNAME] LIKE '%USER1%'
OR t1.[UserNAME] LIKE '%user2%'
OR t1.[UserNAME] LIKE '%user3%')
NOTE: I have altered the way the dates are considered so that an index on [Transaction Date] could be utilized. Instead of calculating a number of months on every row, it is far more efficient to calculate a date then compare existing data to that value. For best performance try to avoid using functions on data in the where clause.
Related
i have this 2 query
select CONVERT(date, en_cours.date),COUNT(*) encours from en_cours group by CONVERT(date, en_cours.date) order by CONVERT(date, en_cours.date) asc
select CONVERT(date, clos.date),COUNT(*) clos from clos group by CONVERT(date, clos.date) order by CONVERT(date, clos.date) asc
the first one return :
B|1
C|1
F|20
and the seconde one :
A|4
B|8
C|7
D|1
E|9
F|10
i'm trying to fusion this 2 query and make it like :
A|4|NULL
B|8|1
C|7|1
D|1|NULL
E|9|NULL
F|10|20
but when i'm doing this it's given different values
select CONVERT(date, clos.date),COUNT(clos.ticket_cp),COUNT(en_cours.ticket_cp)from clos left join en_cours on CONVERT(date, clos.date) = CONVERT(date, en_cours.date) group by CONVERT(date, clos.date) order by CONVERT(date, clos.date) asc
Wrap each of your queries inside a CTE and join them:
with
cte1 as (
select CONVERT(date, en_cours.date) date1, COUNT(*) encours
from en_cours
group by CONVERT(date, en_cours.date)
)
cte2 as (
select CONVERT(date, clos.date) date2, COUNT(*) clos
from clos
group by CONVERT(date, clos.date)
)
select c1.date1, c1.encours, c2.clos
from cte1 c1 left join cte2 c2
on c2.date2 = c1.date1
order by c1.date1 asc
Change the LEFT JOIN to a FULL OUTER JOIN if there is a case that the 2nd query may contain dates that do not exist in the 1st query.
the scenario for using the direct database call is a little fragile, because if you have any database change you will have to wait for the publication time in stores to change queries.
But for your scenario try to include System.Data for integration with sql commands.
I'm working on sales data and I want to know if Customer A purchased product X from more than one provider within 3 days and I'm working on only one date Claim Date
I Can't find T-Sql query for it
for example
SELECT CusName,ProdName,ProvName
FROM table1
WHERE [Claim Date] between Day([Claim Date]) and DATEADD (Day ,-3 , [Claim Date]
A WHERE EXISTS clause should do the job:
SELECT CusName,ProdName,ProvName
FROM table1 a
WHERE EXISTS (
SELECT 1 FROM table1 b WHERE
b.CusName=a.CusName AND
b.ProdName=a.ProdName AND
b.ProvName!=a.ProvName AND
ABS(DATEDIFF(day,a.ClaimDate,b.ClaimDate))<3
)
You can use the below code for that
SELECT t1.CusName,t1.ProdName,t1.ProvName,t2.ProvName
FROM table t1
JOIN table t2 ON t1.CusName=t2.CusName AND t1.ProdName=t2.ProdName
WHERE t1.ProvName!=t2.ProvName
AND ABS(DATEDIFF(day,t1.ClaimDate,t2.ClaimDate)) = 3
You need a having clause and a count of the providers:
SELECT CusName, COUNT(DISTINCT ProvName) Provider_count
FROM table1
WHERE [Claim Date] between Day([Claim Date]) and DATEADD (Day ,-3 , [Claim Date]
AND ProdName = 'X'
GROUP BY CusName
HAVING COUNT(DISTINCT ProvName) > 1
Note, you do not need to include the count in the select clause, but you do need it in the having clause.
I have a table (SYS_Holidays) that have start and end dates of each holiday period. I need to output all holiday dates in a relational form. For example, I have 25-Dec-2017 to 2-Jan-2018 as one row in the input, I want to output 25-Dec, 26-Dec ... through 2-Jan as 9 rows.
I have written this script, could you please tell me how I can make it more efficient?
SELECT
H.HolidayName
, DATEADD(DAY, Number-1, H.StartDate) AS HolidayDate
FROM
SYS_Holidays AS H
CROSS JOIN Config_Numbers AS N
WHERE
-- Figure the # of days between start and end: one row for each holiday-date
-- If EndDate is null, just use StartDate (i.e. 1-day holiday)
N.Number <= DATEDIFF(DAY, H.StartDate, ISNULL(H.EndDate, H.StartDate) ) + 1
NB: Config_Numbers is a table I have created with a huge list of integers (as BIGINT)
It can be done using a date table and an inner join. Use the subquery to make a table if it is not efficient enough:
Create table #Test (HolidayName nvarchar(100), StartDate Date, EndDate Date)
Insert Into #Test Values ('Christmas', '2017-12-22', '2018-01-03'), ('Easter' , '2017-04-10', '2017-04-16')
SELECT HolidayName, DatesList.[Date] as HolidayDate
FROM #Test t
inner join (
SELECT cast(dateadd(day, number, '2017-1-1') as date) as [Date]
FROM master..spt_values WHERE type='P' AND number < 1000) AS DatesList
on t.StartDate<=DatesList.[Date] and t.EndDate>=DatesList.[Date]
I modified #cloudsafe's answer, to yield the code below. It is still much faster than any of the joins using Config_Numbers. Subtree cost came to ~0.2785.
I figured that 2048 can cover a little more than 5 years, so I broke my code up into 5-year blocks, and did a UNION to join them up.
Trouble is, I'd have to remember to do another UNION every 5-years :-(
SELECT HolidayName, DatesList.[Date] as HolidayDate
FROM SYS_Holidays AS H
inner join (
SELECT cast(dateadd(day, number, '2013-01-01') as date) as [Date]
FROM master..spt_values WHERE type='P' AND number < 2048) AS DatesList
on H.StartDate <= DatesList.[Date] and H.EndDate >=DatesList.[Date]
UNION
SELECT HolidayName, DatesList.[Date] as HolidayDate, H.HolidayId, H.CampusId, H.CategoryId
FROM SYS_Holidays AS H
inner join (
SELECT cast(dateadd(day, number, '2018-01-01') as date) as [Date]
FROM master..spt_values WHERE type='P' AND number < 2048) AS DatesList
on H.StartDate <= DatesList.[Date] and H.EndDate >=DatesList.[Date]
Any further suggestions for improvement, please?
I am trying to create a 12 month grid view of all questions that were submitting for each month in that 12 month period.
SELECT
YEAR(h.metaInsert) [Year],
MONTH(h.metaInsert) [Month],
DATENAME(MONTH,h.metaInsert) [Month Name],
COUNT(1) [Total Documents]
FROM
Document_Count_History AS h
WHERE
YEAR(h.metaInsert) = 2017
GROUP BY
YEAR(h.metaInsert), MONTH(h.metaInsert), DATENAME(MONTH, h.metaInsert)
ORDER BY
1, 2
This returns the data perfectly for the months that have it, but I get no data returned for those with 0 records for that specific month.
My goal is to see all 12 months along with the count of documents. If there are no documents, it will simply be a 0 for that month but it will be included in the result set.
How can I take what I have and apply the missing months?
You could use something like this to generate the sequence of months for your query:
declare #StartDate date = '20170101'
,#NumberOfYears int = 1;
;with Months as (
select top (12*#NumberOfYears)
[Month] = dateadd(Month, row_number() over (order by number) -1, #StartDate)
, NextMonth = dateadd(Month, row_number() over (order by number), #StartDate)
from master.dbo.spt_values
)
select
year(m.Month) [Year],
Month(m.Month) [Month],
datename(Month,m.Month) [Month Name],
count(h.*) [Total Documents]
from Months as m
left join Document_Count_History AS h
on h.metaInsert >= m.Month
and h.metaInsert < m.NextMonth
--where h.metaInsert >= '20170101'
group by m.Month
order by m.Month
Although you may want to consider adding a Calendar table, or Date Dimension.
Calendar and Numbers table references:
Generate a set or sequence without loops - 1 - Aaron Bertrand
The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
Creating a Date Table/Dimension in SQL Server 2008 - David Stein
Calendar Tables - Why You Need One - David Stein
Creating a date dimension or calendar table in SQL Server - Aaron Bertrand
An example months table:
create table dbo.Months(
MonthStart date not null primary key
, NextMonthStart date not null
, [Year] smallint not null
, [Month] tinyint not null
, [MonthName] varchar(16) not null
);
declare #StartDate date = '20100101'
,#NumberOfYears int = 30;
insert dbo.Months(MonthStart,NextMonthStart,[Year],[Month])
select top (12*#NumberOfYears)
[MonthStart] = dateadd(month, row_number() over (order by number) -1, #StartDate)
, NextMonthStart = dateadd(month, row_number() over (order by number), #StartDate)
, [year] = year(dateadd(month, row_number() over (order by number) -1, #StartDate))
, [Month] = Month(dateadd(month, row_number() over (order by number) -1, #StartDate))
, MonthName = datename(Month,dateadd(month, row_number() over (order by number) -1, #StartDate))
from master.dbo.spt_values;
and your query would simplify to:
select
m.[Year],
m.[Month],
m.[MonthName],
count(h.*) [Total Documents]
from Months as m
left join Document_Count_History AS h
on h.metaInsert >= m.MonthStart
and h.metaInsert < m.NextMonthStart
where m.Year = 2017
group by m.Month, m.Year, m.MonthName
order by m.MonthStart
You need a date dimension. Specifically, you need a table that has all the values for months. Then, you can do a left-join on the table that gets the totals, and pull out a sum value.
I've struggled to search successfully for this as I haven't figured out a search string describing what I want to do, apologies if this has been covered already.
I have a table that contains among others a contract number, a start date, a serial number and a datestamp. These are Many:Many.
What I'm trying to achieve is to return the start date for each individual contract number with the largest number of unique serial numbers and the most recent datestamp, where that start date is valid.
This, as I guess is obvious to T-SQL experts only returns me the one contract number with the largest number of serials. Can anyone tell me what I'm doing wrong?
SELECT TOP (1)
[Contract ID], [Item Begin Date] AS Start_Date,
COUNT([Serial Number]) AS CountSerials,
Datestamp
FROM
SourceTable
GROUP BY
[Contract ID], [Item Begin Date], Datestamp
HAVING
([Item Begin Date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102))
ORDER BY
CountSerials DESC, Datestamp DESC
Cheers,
Alex
You can put that into a temporary table (without using TOP (1) or oder by):
I changed some table names in the process,
if exists (select * from tempdb.sys.tables where name = '##tmp')
drop table ##tmp
SELECT * into ##tmp
from
(
select
[Contract_ID], [Begin_Date] AS Start_Date,
COUNT([serials]) AS CountSerials,
Datestamp
FROM
SourceTable
GROUP BY
[Contract_ID], [begin_date], Datestamp
HAVING
[begin_date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102)
) a
select contract_id,Start_Date, max(countserials) as MAXCOUNT, Datestamp from ##tmp
group by contract_id,Start_Date,Datestamp
you can do a subquery with aggregation and extract your desired results from it:
SELECT distinct *
FROM
(
Select
[Contract ID], [Item Begin Date] AS Start_Date,
COUNT([Serial Number]) OVER(PARTITION BY [Contract ID]) AS CountSerials,
datestamp,
MAX(Datestamp) OVER (PARTITION BY [Contract ID]) maxdatestamp
FROM
SourceTable
WHERE
([Item Begin Date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102))
) x
WHERE
datestamp=maxdatestamp