I want to convert inner join Query in SubQuery - sql-server

I am using inner join in query but I want Subquery instead of join
select [Document No_] as DocumentNo,
ledger.[Posting Date] as Date,
[Sales (LCY)] as Amount,
header.[Customer Reference] as PONo
from [Uneek Clothing Company Ltd$Cust_ Ledger Entry] ledger
inner join [Uneek Clothing Company Ltd$Sales Invoice Header] header on ledger.[Entry No_]=header.[Cust_ Ledger Entry No_]
where [Customer No_] = 'DRC01'
and [Document Type]=2
and [Sales (LCY)]!=0
and ledger.[Posting Date] between '01/01/2019' and '12/31/2019'
order by [Sales (LCY)] asc offset 0 ROWS FETCH NEXT 20 ROWS ONLY
[Entry No_] is foreign key in [Uneek Clothing Company Ltd$Sales Invoice Header] with name [Cust_ Ledger Entry No_]

if you really want to drop the join and use a subquery instead,
it will look something like this.
Since you did not use an table alias for all columns, I had to assume that no other column of table in the subquery is used anywhere else. If that is not the case then this will not work
It will also only work if the subquery returns no more then 1 row, otherwise a subquery cannot be used at all
select [Document No_] as DocumentNo,
ledger.[Posting Date] as Date,
[Sales (LCY)] as Amount,
( select header.[Customer Reference]
from [Uneek Clothing Company Ltd$Sales Invoice Header] header
where ledger.[Entry No_] = header.[Cust_ Ledger Entry No_]
) as PONo
from [Uneek Clothing Company Ltd$Cust_ Ledger Entry] ledger
where [Customer No_] = 'DRC01'
and [Document Type]=2
and [Sales (LCY)]!=0
and ledger.[Posting Date] between '01/01/2019' and '12/31/2019'
order by [Sales (LCY)] asc
offset 0 ROWS FETCH NEXT 20 ROWS ONLY

Related

Scheduled datetime conversion error (SQL)

When trying to convert a datetime field to get rid of NULL's I am getting the error that the datetime cannot be converted.
This query is populating another database where the column datatype is date.
This job runs perfectly fine when not scheduled, but results in an error during the scheduled insert job.
Any ideas?
, (SELECT
CASE
WHEN MIN([Discount Ledger].[Posting Date]) IS NOT NULL
THEN CONVERT(VARCHAR(50), MIN([Discount Ledger].[Posting Date]), 121)
ELSE '-'
END
FROM
[Wings$Discount Ledger Entry] AS "Discount Ledger"
LEFT JOIN
[Wings$Periodic Discount] AS "MixMatchHeader" ON [Discount Ledger].[Offer No_] = [MixMatchHeader].[No_]
LEFT JOIN
[Wings$Periodic Discount Line] AS "MixMatch" ON [MixMatchHeader].[No_] = [MixMatch].[Offer No_]
LEFT JOIN
[Wings$Item_Special Group Link] AS "Special Group" ON [MixMatch].[No_] = [Special Group].[Special Group Code]
LEFT JOIN
[Wings$Store Price Group] AS "Store Price Group" ON [MixMatch].[Price Group] = [Store Price Group].[Price Group Code]
WHERE
[MixMatch].[No_] = [Item Ledger].[Item No_]
AND [MixMatch].[Variant Code] = [Item Ledger].[Variant Code]
AND [Store Price Group].[Store] = [Item Ledger].[Location Code]) AS "Discount Start Date"
You can do this using ISNULL. Since you are looking for the MIN date, I will use GETDATE() as the argument/replacement value for NULL. Unless your data has future dates, then GETDATE() should function as the MAX value. Unless you want the CASE statement to evaluate the NULL values as the MIN. In that case, you can use an empty string '' or '1900-01-01' instead of GETDATE().
, (SELECT
CASE
WHEN
MIN([Discount Ledger].[Posting Date]) IS NOT NULL
THEN CONVERT(varchar(50),MIN(ISNULL([Discount Ledger].[Posting Date],GETDATE())),121)
ELSE '-'
END
FROM [Wings$Discount Ledger Entry] AS "Discount Ledger"
LEFT JOIN [Wings$Periodic Discount] AS "MixMatchHeader" ON [Discount Ledger].[Offer No_] = [MixMatchHeader].[No_]
LEFT JOIN [Wings$Periodic Discount Line] AS "MixMatch" ON [MixMatchHeader].[No_] = [MixMatch].[Offer No_]
LEFT JOIN [Wings$Item_Special Group Link] AS "Special Group" ON [MixMatch].[No_] = [Special Group].[Special Group Code]
LEFT JOIN [Wings$Store Price Group] AS "Store Price Group" ON [MixMatch].[Price Group] = [Store Price Group].[Price Group Code]
WHERE [MixMatch].[No_] = [Item Ledger].[Item No_] AND [MixMatch].[Variant Code] = [Item Ledger].[Variant Code] AND [Store Price Group].[Store] = [Item Ledger].[Location Code])
AS "Discount Start Date"

SQL - Returning only the most recent row

I'm working on aging report for accounts over 30 days and I am joining the "Comment" table because AP wants to see the most recent comment if it exists for a customer.
The comment table can have multiple rows for the same customer for each comment that is attached to that customer with the first record being the oldest comment.
When I join the tables everything works, but it returns the first comment not the latest.
How can I get it to to look for multiple rows for the same customer and then return the most recent comment?
*Note - The comment table does not have dates just a field the starts at 1000 and increases for each new comment row
This is what i have right now:
SELECT
dbo.[Pioneer-CO$Purchase Header].No_,
dbo.[Pioneer-CO$Purchase Line].[Amt_ Rcd_ Not Invoiced],
dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date],
dbo.[Pioneer-CO$Comment Line].[Comment],
dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_]
FROM
dbo.[Pioneer-CO$Purchase Header]
INNER JOIN
dbo.[Pioneer-CO$Purchase Line] ON dbo.[Pioneer-CO$Purchase Header].No_ = dbo.[Pioneer-CO$Purchase Line].[Document No_]
INNER JOIN
dbo.[Pioneer-CO$Purch_ Rcpt_ Header] ON dbo.[Pioneer-CO$Purchase Header].No_ = dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Order No_]
INNER JOIN
dbo.[Pioneer-CO$Comment Line] ON dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_] = dbo.[Pioneer-CO$Comment Line].[No_]
WHERE
(dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date] < DATEADD(day, - 30, GETDATE()))
GROUP BY
dbo.[Pioneer-CO$Purchase Header].No_,
dbo.[Pioneer-CO$Purchase Line].[Amt_ Rcd_ Not Invoiced],
dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date],
dbo.[Pioneer-CO$Comment Line].[Comment],
dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_]
HAVING
(dbo.[Pioneer-CO$Purchase Line].[Amt_ Rcd_ Not Invoiced] > '0')
ORDER BY
dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date] DESC
I would use something like this
select customer.*, lastComment.*
from account
cross apply (select top 1 * from comment where
comment.customerId=customer.customerId order by commentnumber desc) lastComment
where customer.age>30
If you need to include customers without comments use outer apply instead of cross apply
I would use following query:
OUTER APPLY
(select top 1 [Comment] from dbo.[Pioneer-CO$Comment Line] where dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_] = dbo.[Pioneer-CO$Comment Line].[No_] order by [Posting Date] desc) Comments
Also, use Comments.[Comment] in the SELECT statement instead of dbo.[Pioneer-CO$Comment Line].[Comment]
The dbo.[Pioneer-CO$Comment Line] table should be OUTER APPLY join in the query. Also, order by comments posting date or incremental ID.
You should look at the ID or primary key, I'd imagine the newer comments have a higher ID. You could join the tables and do a Max(ID) or look for the latest timestamp if you use that on your table.
Looks like you have Customers to Comments relationship is 1 to Many(0).
How about trying something like this,
SELECT TOP 1 Customers.*, Comments.*
FROM Customers
JOIN Customers ON Customers.Id = Comments.Id
ORDER BY Comments.Id DESC
Following Added after Bib's comments
You can also try following
SELECT Customers.*, Comments.*
FROM Comments
JOIN
(SELECT MAX(Id) As CId FROM Comments GROUP BY CustomerId) AS CommentsMAX
ON CommentsMAX.CId = Comments.ID
JOIN
Customers ON Customers.Id = Comments.Id

Using a range with GETDATE & BETWEEN

I'm fairly new to T-SQL and am still learning so please bear with me on this one...I've tried several ways to do this with no luck. I have my 'current' and 90+ days but it's the 30 and 60 days that I'm struggling with. Why can't I use the 'between' clause?
,[CURRENT]=(SELECT sum (cle.[Amount])
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3 left outer join
[NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle on cl3.[entry no_]=cle.[cust_ ledger entry no_]
where C.[NO_]=CL3.[CUSTOMER NO_] AND cl3.[open]='1' AND cl3.[Due Date]>getdate()-30)
,[30 DAYS]=(SELECT sum (cle.[Amount])
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3 left outer join
[NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle on cl3.[entry no_]=cle.[cust_ ledger entry no_]
where C.[NO_]=CL3.[CUSTOMER NO_] AND cl3.[open]='1' AND cl3.[Due Date]BETWEEN GETDATE()-31 AND getdate()-59)
,[60 DAYS]=(SELECT sum (cle.[Amount])
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3 left outer join
[NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle on cl3.[entry no_]=cle.[cust_ ledger entry no_]
where C.[NO_]=CL3.[CUSTOMER NO_] AND cl3.[open]='1' AND cl3.[Due Date] BETWEEN GETDATE()-60 AND getdate()-89)
,[90 + DAYS]=((SELECT sum (cle.[Amount])
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3 left outer join
[NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle on cl3.[entry no_]=cle.[cust_ ledger entry no_]
where C.[NO_]=CL3.[CUSTOMER NO_] AND cl3.[open]='1' AND cl3.[Due Date]<=getdate()-90 ))
I know there are entries for that particular customer in both of those buckets.
suggestions?
When filtering a range of dates, BETWEEN expects the earlier date to come before the later date.
You need to reverse the sides of the BETWEEN so that the older date (with highest -value) comes first:
,[30 DAYS]=(SELECT sum (cle.[Amount])
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3 left outer join
[NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle on cl3.[entry no_]=cle.[cust_ ledger entry no_]
where C.[NO_]=CL3.[CUSTOMER NO_] AND cl3.[open]='1' AND cl3.[Due Date]BETWEEN GETDATE()-59 AND getdate()-31)
,[60 DAYS]=(SELECT sum (cle.[Amount])
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3 left outer join
[NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle on cl3.[entry no_]=cle.[cust_ ledger entry no_]
where C.[NO_]=CL3.[CUSTOMER NO_] AND cl3.[open]='1' AND cl3.[Due Date] BETWEEN GETDATE()-89 AND getdate()-60)
Instead of four separate subqueries, you can use one query with CASE statements
SELECT
[CURRENT] = SUM(CASE WHEN cl3.[Due Date] >= DATEADD(day,-30,GETDATE())
THEN cle.[Amount]
END)
,[30 DAYS] = SUM(CASE WHEN cl3.[Due Date] < DATEADD(day,-30,GETDATE())
AND cl3.[Due Date] >= DATEADD(day,-60,GETDATE())
THEN cle.[Amount]
END)
,[60 DAYS] = SUM(CASE WHEN cl3.[Due Date] < DATEADD(day,-60,GETDATE())
AND cl3.[Due Date] >= DATEADD(day,-90,GETDATE())
THEN cle.[Amount]
END)
,[90 DAYS] = SUM(CASE WHEN cl3.[Due Date] < DATEADD(day,-90,GETDATE())
THEN cle.[Amount]
END)
FROM [NISNAV].[dbo].[NIS$Cust_ Ledger Entry] cl3
LEFT OUTER JOIN [NISNAV].[dbo].[NIS$Detailed Cust_ Ledg_ Entry] cle
ON( cl3.[entry no_]=cle.[cust_ ledger entry no_])
WHERE C.[NO_]=CL3.[CUSTOMER NO_]
AND cl3.[open]='1'

How to return top 30 customer revenue combines from service and sales table

I can pull the individual rows with this query but want to combine the two tables and show, by customer No, the top 30 customer by salesperson.
select top 30 sil.[Sell-to Customer No_]as 'Customer No.',
cus.[Name],
sil.[Responsibility Center],
sil.[Amount] as 'Total',
'SALES'
FROM [Sales Invoice Line] sil left outer join [Customer]cus
on sil.[Sell-to Customer No_] = cus.[No_]
where sil.[Amount] > 0
and sil.[Responsibility Center] != 'cis'
and sil.[Posting Date] between '10-01-13' and (current_timestamp)
group by sil.[Amount], sil.[Sell-to Customer No_], sil.[Responsibility Center], cus.[Name]
union all
select top 30 sil.[Customer No_],
cus.[Name],
sil.[Responsibility Center],
sil.[Amount] as 'Total',
'SERVICE'
FROM [Service Invoice Line] sil left outer join [Customer]cus
on sil.[Customer No_] = cus.[No_]
where sil.[Amount] > 0
and sil.[Responsibility Center] != 'cis'
and sil.[Posting Date] between '10-01-13' and (current_timestamp)
group by sil.[Amount], sil.[Customer No_], sil.[Responsibility Center], cus.[Name]
Wrap your entire query that returns 60 rows with a query to get the top 30.
select top 30 x, y, z
from (
select top 30 x, y, z from a where blah
union all
select top 30 x, y, z from b where blah
) x --here's the alias for the subquery
order by topcriteria
The order by is important so you get the proper "top" of the query.
Edit: Here's your sum example:
select top 30 sil.[Sell-to Customer No_]as 'Customer No.',
cus.[Name],
sil.[Responsibility Center],
sum(sil.[Amount]) as 'Total',
'SALES'
FROM [Sales Invoice Line] sil left outer join [Customer]cus
on sil.[Sell-to Customer No_] = cus.[No_]
where sil.[Amount] > 0
and sil.[Responsibility Center] != 'cis'
and sil.[Posting Date] between '10-01-13' and (current_timestamp)
group by sil.[Sell-to Customer No_], sil.[Responsibility Center], cus.[Name]

How to return NULL value is no records are found in multiple join conditions

I'm creating a report where i need to show all Purchase Indents as per filters and corresponding purchase lines of these indent lines.
If there is no purchase line found as per my condition then it should return NULL value. But report is not showing Indents for which there are no records in purchase lines.
I'm joining 4 tables - INH,INL,PL,PH. The Query is shown below.
SELECT
INH.No_
,INH.[Approved Date]
,INH.Indentor
,INL.No_ AS ItemCode
,INL.description
,INL.Description2
,INL.Req_Quantity
,INL.[Unit of Measure]
,PL.[Document No_]
,PH.[Order Date]
,PL.Quantity AS OrderedQuantity
,PL.[Quantity Received]
FROM [ICTL | HYDERABAD$Indent Header] AS INH
INNER JOIN [ICTL | HYDERABAD$Indent Line] AS INL ON INH.No_ = INL.[Document No_]
LEFT OUTER JOIN [ICTL | HYDERABAD$Purchase Line] AS PL ON INL.[Document No_] = PL.[Indent No_] AND INL.[Line No_] = PL.[Indent Line No_]
LEFT OUTER JOIN [ICTL | HYDERABAD$Purchase Header] AS PH ON PL.[Document No_] = PH.No_
WHERE (UPPER(INH.Indentor) = UPPER(#Name)
OR #Name IS NULL)
AND (INL.No_ <> '')
AND (INH.[Approved Date] >= #StartDate
OR #StartDate IS NULL)
AND (INH.[Approved Date] <= #EndDate
OR #EndDate IS NULL)
AND (PL.[Document Type] = 1)
ORDER BY ItemCode
The problem is that you are have PL.[Document Type] = 1 in your query. This will automatically exclude all rows where there is no PL record (your OUTER JOIN does not matter then).
Either you'd have to do PL.[Document Type] IS NULL OR PL.[Document Type] = 1 in the WHERE clause, or you'd have to add the PL.[Document Type] = 1 to the JOIN condition of the PL table.
Possible this be helpful for you -
SELECT
INH.No_
, INH.[Approved Date]
, INH.Indentor
, INL.No_ AS ItemCode
, INL.description
, INL.Description2
, INL.Req_Quantity
, INL.[Unit of Measure]
, PL.[Document No_]
, PH.[Order Date]
, PL.Quantity AS OrderedQuantity
, PL.[Quantity Received]
FROM [ICTL | HYDERABAD$Indent Header] INH
JOIN [ICTL | HYDERABAD$Indent Line] INL ON INH.No_ = INL.[Document No_]
LEFT JOIN [ICTL | HYDERABAD$Purchase Line] PL ON INL.[Document No_] = PL.[Indent No_] AND INL.[Line No_] = PL.[Indent Line No_]
LEFT JOIN [ICTL | HYDERABAD$Purchase Header] PH ON PL.[Document No_] = PH.No_
WHERE UPPER(INH.Indentor) = UPPER(ISNULL(#Name, INH.Indentor))
AND INL.No_ <> ''
AND INH.[Approved Date] BETWEEN ISNULL(#StartDate, '19000101') AND ISNULL(#EndDate, '30000101')
AND ISNULL(PL.[Document Type], 1) = 1
ORDER BY ItemCode

Resources