SQL Where 2 values one is empty - sql

I'm struggling whit some SQL code for some hours now. I'm trying to combine 2 different values in one row, but if one value is not there (so no result) there will not row at all.
To be more clear: I have a Location whit 2 different values, those are coming from two queries. That is working fine, but sometime the second query give no results (can happen, is not bad), but than also the first value is not shown.
Declare #Start datetime,
#Ende datetime;
SET #Start = '01.04.2015';
SET #Ende = '30.04.2015';
SELECT t1.[Location Code], CAST(t1.Umsatz as DECIMAL(18,2))as Umsatz , CAST(t2.Ersatznachweis as DECIMAL(18,2)) as Ersatznachweis
FROM (
SELECT [Location Code], SUM(WareBrutto) AS Umsatz
FROM (SELECT DISTINCT [Location Code], [Document No_] , WareBrutto from [Item Ledger Entry]
WHERE [Location Code] > '0000' and [Location Code] < '0040' and [Document Date] >= #Start and [Document Date] <= #Ende) t
GROUP BY [Location Code]) as t1,
(select [Location Code], sum([Quantity]*Bruttopreis) as Ersatznachweis from [Item Ledger Entry]
where [Location Code] > '0000' and [Location Code] < '0040' and [Item No_] not IN ('00009000','00009900','00009906') and Gutschrift = '1' and [Document Date] >= #Start and [Document Date] <= #Ende
Group By [Location Code]) as t2
where t1.[Location Code] = t2.[Location Code]
order by t1.[Location Code]
It is the second query that sometimes does not return a value.
(select [Location Code], sum([Quantity]*Bruttopreis) as Ersatznachweis from [Item Ledger Entry]
where [Location Code] > '0000' and [Location Code] < '0040' and [Item No_] not IN ('00009000','00009900','00009906') and Gutschrift = '1' and [Document Date] >= #Start and [Document Date] <= #Ende
Group By [Location Code]) as t2
But that when it comes to the end and there is no result of t2.[Location code] the result of t1 is also not shown.
where t1.[Location Code] = t2.[Location Code]
I want that t2 gets a value of zero when there is no result. I tried isnull and the coalesec option but I was not able to get a decent result. It is just not there or I get error messages.
Thank in advanced...
Using Toad for SQl on a 2012 MSSQL server.

The problem is that the comma join and where clause you're using makes the join an inner join (Thanks to the comment from Ed B for adding details to this). In an inner join, only matching records are shown. Since there are no records in t2, nothing is matching in t1, and no records are returned. You're looking for a LEFT join, which will join any matching records from the 2nd table to the returned records from the 1st table. If nothing is in the 2nd table, you still get all of the original records from the 1st table.
I've updated your code so it uses a LEFT join, does the join in an ON statement instead of a where, and uses COALESCE to show 0 instead of NULL for records that don't match.
The following should get what you're looking for:
Declare #Start datetime,
#Ende datetime;
SET #Start = '01.04.2015';
SET #Ende = '30.04.2015';
SELECT t1.[Location Code], CAST(t1.Umsatz as DECIMAL(18,2))as Umsatz , CAST(COALESCE(t2.Ersatznachweis, 0) as DECIMAL(18,2)) as Ersatznachweis
FROM (
SELECT [Location Code], SUM(WareBrutto) AS Umsatz
FROM (SELECT DISTINCT [Location Code], [Document No_] , WareBrutto from [Item Ledger Entry]
WHERE [Location Code] > '0000' and [Location Code] < '0040' and [Document Date] >= #Start and [Document Date] <= #Ende) t
GROUP BY [Location Code]) as t1
LEFT JOIN (select [Location Code], sum([Quantity]*Bruttopreis) as Ersatznachweis from [Item Ledger Entry]
where [Location Code] > '0000' and [Location Code] < '0040' and [Item No_] not IN ('00009000','00009900','00009906') and Gutschrift = '1' and [Document Date] >= #Start and [Document Date] <= #Ende
Group By [Location Code]) as t2 ON t1.[Location Code] = t2.[Location Code]
order by t1.[Location Code]

You should use a better syntax in your statements. Use a join instead of select from 2 comma seperated tables.
Then you'll see that you'll need a left join.
SELECT ... AS t1
LEFT JOIN
(SELECT ...) AS t2 ON t1.[Location Code] = t2.[Location Code]
...

Related

SQL replace int in string by text

I'm trying to do a query but in my result I have a column with the number '2' which I want to be replaced by 'factura'.
How can I do this?? I want to replace Cust.[Document Type] column
SELECT Detail.[Entry No_],
'Cliente' AS Tipo,
Cust.[Customer No_] AS Cliente,
Detail.[Posting Date] AS DATA,
Detail.[Document No_] AS Documento,
Detail.[Amount (LCY)] AS Valor,
Cust.[Document Type] AS LiqPorTipo,
Cust.[Document No_] AS LiqPorNDocumento,
'97' AS Conta,
'MR' AS Loja,
'SUPER' AS Utilizador,
'MR01' AS POS
FROM dbo.MBS_tabela_21Detailed_NAV16 AS Detail
INNER JOIN dbo.MBS_tabela_21_NAV16 AS Cust ON Detail.[Cust_ Ledger Entry No_] = Cust.[Entry No_]
INNER JOIN dbo.Integracao_Periodo_NAV16 AS Integr ON YEAR(Detail.[Posting Date]) = Integr.Ano
AND MONTH(Detail.[Posting Date]) = Integr.Mes
WHERE (Detail.[Document No_] LIKE '%REC%'
OR Detail.[Document No_] LIKE '%L%')
AND (Detail.[Entry Type] = 2)
AND (Cust.[Global Dimension 1 Code] = 'LMR')
this results in
359229 Cliente 503392154 2018-03-23 00:00:00.000 1803PAGLEITE37 -2064,62000000000000000000 2 MRVFFT1800012 97 MR SUPER MR01
and i want to have
359229 Cliente 503392154 2018-03-23 00:00:00.000 1803PAGLEITE37 -2064,62000000000000000000 fatura MRVFFT1800012 97 MR SUPER MR01
Your query is missing "Detail.[Entry Type] column". Comparing expected query result and your query result I assume you would like to use either case or create dictionary table to join it.
Best option would be to create additional table and store there all key-value translations.
So you could have
2 - factura
And join it in your query.
If not you should do like this:
SELECT Detail.[Entry No_],
'Cliente' AS Tipo,
Cust.[Customer No_] AS Cliente,
Detail.[Posting Date] AS DATA,
Detail.[Document No_] AS Documento,
Detail.[Amount (LCY)] AS Valor,
case when Cust.[Document Type] = 2 then 'factura' else '' end AS LiqPorTipo,
Cust.[Document No_] AS LiqPorNDocumento,
'97' AS Conta,
'MR' AS Loja,
'SUPER' AS Utilizador,
'MR01' AS POS
FROM dbo.MBS_tabela_21Detailed_NAV16 AS Detail
INNER JOIN dbo.MBS_tabela_21_NAV16 AS Cust ON Detail.[Cust_ Ledger Entry No_] = Cust.[Entry No_]
INNER JOIN dbo.Integracao_Periodo_NAV16 AS Integr ON YEAR(Detail.[Posting Date]) = Integr.Ano
AND MONTH(Detail.[Posting Date]) = Integr.Mes
WHERE (Detail.[Document No_] LIKE '%REC%'
OR Detail.[Document No_] LIKE '%L%')
AND (Detail.[Entry Type] = 2)
AND (Cust.[Global Dimension 1 Code] = 'LMR')
As you want to replace one column base on join result. Bellow structure may help you
UPDATE
Table_A
SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2
FROM
Some_Table AS Table_A
INNER JOIN Other_Table AS Table_B
ON Table_A.id = Table_B.id
WHERE
Table_A.col3 = 'cool'
Base on above structure your sql scritp is bellow.
UPDATE Detail
SET Detail.[Entry Type] = REPLACE(Detail.[Entry Type], '2', 'factura')
FROM dbo.MBS_tabela_21Detailed_NAV16 AS Detail
INNER JOIN dbo.MBS_tabela_21_NAV16 AS Cust
ON Detail.[Cust_ Ledger Entry No_] = Cust.[Entry No_]
INNER JOIN dbo.Integracao_Periodo_NAV16 AS Integr
ON YEAR(Detail.[Posting Date]) = Integr.Ano
AND MONTH(Detail.[Posting Date]) = Integr.Mes
WHERE (Detail.[Document No_] LIKE '%REC%'
OR Detail.[Document No_] LIKE '%L%')
AND (Detail.[Entry Type] = 2)
AND (Cust.[Global Dimension 1 Code] = 'LMR')

How to SQL join payments with invoices in NAV Dynamics (former Navision)

The question is about SQL fiddling in Dynamics Nav tables, especially the table [$Vendor Ledger Entry]. How to link each payment to appropriate invoices.
The aim is to get [External Document No_] and [Amount] of the invoice. One payment can be matched with many invoices (happens) or one invoice with many payments (rare case).
My desperate approach is:
;with cte as
(
select
*
,[Row_max]=max([Row]) OVER(PARTITION BY CBEN,[Document Type])
from (
select
*
,[Row]=ROW_NUMBER() OVER(PARTITION BY CBEN,[Document Type] ORDER BY [Entry No_] asc)
from (
select
*
,CBEN=case when [Closed by Entry No_]=0 then [Entry No_] else [Closed by Entry No_] end
from [CompanyName$Vendor Ledger Entry] --here put correct table name
) tb1
) tb2
)
select
a.[Entry No_] [Entry No_payment] -- letter t means transfers
,b.[Entry No_] [Entry No_invoice] -- letter p means payables
--,a.CBEN as CBEN_t
--,b.CBEN as CBEN_p
--,a.[Row_max] as Row_max_t
--,b.[Row_max] as Row_max_p
--,a.[Row] as Row_t
--,b.[Row] as Row_p
,a.[Open]
,b.[External Document No_] [External Document No_invoice]
,a.[Document No_] [Document No_payment]
,b.[Document No_] [Document No_invoice]
,b.[Document Date]
,b.[Posting Date]
,b.[Due Date]
,Amount_p=b.[Closed by Amount]
--,a.[Company]
from cte a
left join cte b
on
(
a.CBEN=b.CBEN and -- join using Closed By Entry No
(a.[Row]=b.[Row] and a.[Row_max]=b.[Row_max] or
a.Row_max=1 and not (a.[Row_max]>1 and b.[Row_max]>1) or
b.Row_max=1 and not (a.[Row_max]>1 and b.[Row_max]>1)
) and
a.[Document Type] in (0,1) and
b.[Document Type]=2
and a.[Open]=0
)
or
(
a.CBEN = b.[Entry No_] and -- or join by Closed By Entry No to EntryNo
(a.[Row]=b.[Row] and a.[Row_max]=b.[Row_max] or
a.Row_max=1 and not (a.[Row_max]>1 and b.[Row_max]>1) or
b.Row_max=1 and not (a.[Row_max]>1 and b.[Row_max]>1)
) and
a.[Document Type] in (0,1) and
b.[Document Type]=2
and a.[Open]=0
)
where
a.[Open]=0 and a.[Document Type] in (0,1) and b.[Entry No_] is not null -- show payments with matched invoices
or
a.[Open]=1 and a.[Document Type] in (0,1) and b.[Entry No_] is null -- or payments with open status
order by a.CBEN,1,2,a.[Document No_]
I am at a loss to join Invoice [Amount] and I do not know in which Dynamics NAV table it might be.
the table is
[Detailed Vendor Ledg. Entry]
with [Entry Type] = Application

How do i sum data from 2 tables left joined to 1 table?

When I comment out all lines pertaining to either the "Sales Line" or "Warehouse Entry" table the query works as expected. But when I use this query as is; it returns faulty(unrealistically high by at least 5 digits) data.
The idea is to iterate the "Item" table and to obtain the amount in stock as well as the sum of quantity sold as well as It's worth. I think there must be something wrong by the way I'm joining these tables. Both "Warehouse Entry" and "Sales Line" table have multiple entries that can be linked to I.[No_].
USE NAV2009_R2_SHOWTEX_LIVE
SELECT I.[No_]
,sum(S.[Quantity (Base)]) AS [Quantity Sold]
,min(I.[IP Total (Manual)]) * sum(WE.[Quantity]) AS [Stock Value]
,sum(WE.[Quantity]) AS [Quantity Stock]
FROM [Item] AS I
INNER JOIN [Warehouse Entry] AS WE ON WE.[Item No_] = I.[No_]
AND WE.[Location Code] = 'BU'
AND WE.[Bin Code] <> 'SHIPPING'
AND WE.[Bin Code] <> 'WORKSHOP'
AND WE.[Bin Code] <> 'OUTBOX'
AND WE.[Bin Code] <> 'CUT'
AND WE.[Bin Code] <> 'VERZEND'
INNER JOIN [Sales Line] AS S ON S.[No_] = I.[No_]
AND S.[Shipment Date] > '07/01/2015'
AND S.[Document Type] = 1
WHERE I.[No_] LIKE '140003000007'
GROUP BY I.[No_]
Sample Data
No.|Quantity Sold|Stock Value|Quantity Stock
Wrong Data
140003000007|204484537.36000000000000000000|13051602.124400| 2355884.86000000000000000000
Right Data
140003000007|61703.24000000000000000000|13623.801800|2459.17000000000000000000
SELECT sumQuantityBase as [Quantity Sold],
minIP * sumQuantityBase as [Stock Value],
sumQuantityBase as [Quantity Stock]
FROM
(SELECT MIN(I.[IP Total (Manual)] )as minIP,
No_
FROM I
WHERE [No_] like '140003000007'
GROUP BY No_) MinI INNER JOIN
(SELECT SUM([Quantity]) as sumQuantity,
[Item No_]
FROM WE
WHERE [Location Code] = 'BU'
AND [Bin Code] <> 'SHIPPING'
AND [Bin Code] <> 'WORKSHOP'
AND [Bin Code] <> 'OUTBOX'
AND [Bin Code] <> 'CUT'
AND [Bin Code] <> 'VERZEND'
GROUP BY [Item No_] ) SumWE
ON MinI.[No_] = SumWE[Item No_] INNER JOIN
(SELECT SUM([Quantity (Base)]) as sumQuantityBase,
No_
FROM S
WHERE [Shipment Date] > '07/01/2015'
AND [Shipment Date] IS NOT NULL
AND [Document Type] = 1
GROUP BY No_ ) SumS
ON SumS.[No_] = MinI.[No_]
Try this one. When you want to aggregate data using sum or min function i'd recommend you do it in a subset. that way you keep it simple

Pass value in a Variable

I want to pass the value of 1 of my columns in my SELECT statements in a Variable.
Here's my sample code:
DECLARE #TotalExpense DECIMAL(18,2)
SELECT a.[Posting Date] AS [Check Date],
a.[Document No_] AS [Check Number],
a.[Vendor No_],
(
SELECT SUM(CASE WHEN GLEntry.[VAT Amount] <> 0 THEN CAST(GLEntry.Amount AS DECIMAL(18,2)) ELSE 0 END) FROM [BLI$Detailed Vendor Ledg_ Entry] DtldVendLedger
LEFT JOIN [BLI$G_L Entry] GLEntry
ON GLEntry.[Document No_] = (SELECT VendLedger.[Document No_] FROM [BLI$Vendor Ledger Entry] VendLedger
WHERE VendLedger.[Entry No_] = DtldVendLedger.[Vendor Ledger Entry No_])
WHERE DtldVendLedger.[Entry Type] = 2 AND DtldVendLedger.[Initial Document Type] = 2 AND DtldVendLedger.[Document No_] = a.[Document No_]
AND GLEntry.[Source Code] = 'PURCHASES' AND GLEntry.[G_L Account No_] NOT IN ('2003','1402','1403','1401')
) AS [Vatable],
(
SELECT SUM(CASE WHEN GLEntry.[VAT Amount] <> 0 THEN CAST(GLEntry.Amount * 0.12 AS DECIMAL(18,2)) ELSE 0 END) FROM [BLI$Detailed Vendor Ledg_ Entry] DtldVendLedger
LEFT JOIN [BLI$G_L Entry] GLEntry
ON GLEntry.[Document No_] = (SELECT VendLedger.[Document No_] FROM [BLI$Vendor Ledger Entry] VendLedger
WHERE VendLedger.[Entry No_] = DtldVendLedger.[Vendor Ledger Entry No_])
WHERE DtldVendLedger.[Entry Type] = 2 AND DtldVendLedger.[Initial Document Type] = 2 AND DtldVendLedger.[Document No_] = a.[Document No_]
AND GLEntry.[Source Code] = 'PURCHASES' AND GLEntry.[G_L Account No_] NOT IN ('2003','1402','1403','1401')
) AS [Input Tax],
(
SELECT SUM(CASE WHEN GLEntry.[VAT Amount] = 0 THEN CAST(GLEntry.Amount AS DECIMAL(18,2)) ELSE 0 END) FROM [BLI$Detailed Vendor Ledg_ Entry] DtldVendLedger
LEFT JOIN [BLI$G_L Entry] GLEntry
ON GLEntry.[Document No_] = (SELECT VendLedger.[Document No_] FROM [BLI$Vendor Ledger Entry] VendLedger
WHERE VendLedger.[Entry No_] = DtldVendLedger.[Vendor Ledger Entry No_])
WHERE DtldVendLedger.[Entry Type] = 2 AND DtldVendLedger.[Initial Document Type] = 2 AND DtldVendLedger.[Document No_] = a.[Document No_]
AND GLEntry.[Source Code] = 'PURCHASES' AND GLEntry.[G_L Account No_] NOT IN ('2003','1402','1403','1401')
) AS [Non-Vat]
I want to Sum the Vatable, Input Tax, and Nonvat then pass the value into a variable then that variable will be used in my SELECT statements.
I tried to rearrange your query a bit. In your query the part with the DtldVendLedger query inside the join condition should not be valid. If you got that to run I have no idea how.
Because of the way I think you're summing I don't think it matters whether you used outer joins or inner joins. The rows with null GLEntry count as zeroes anyway.
DECLARE #vatable DECIMAL(18, 2);
DECLARE #inputtax DECIMAL(18, 2);
DECLARE #nonvat DECIMAL(18, 2);
SELECT
#vatable = SUM(
CASE
WHEN GLEntry.[VAT Amount] <> 0
THEN CAST(GLEntry.Amount AS DECIMAL(18,2)) ELSE 0 END
),
#nonvat = SUM(
CASE
WHEN GLEntry.[VAT Amount] = 0
THEN CAST(GLEntry.Amount AS DECIMAL(18,2)) ELSE 0 END
)
FROM
A as a /* I'm assuming there was a FROM referencing a table "a" */
[BLI$Detailed Vendor Ledg_ Entry] DtldVendLedger
INNER JOIN
ON DtldVendLedger.[Document No_] = a.[Document No_]
LEFT OUTER JOIN [BLI$Vendor Ledger Entry] VendLedger
ON VendLedger.[Entry No_] = DtldVendLedger.[Vendor Ledger Entry No_]
LEFT OUTER JOIN [BLI$G_L Entry] GLEntry
ON GLEntry.[Document No_] = VendLedger.[Document No_]
WHERE
a.??? = ???
AND DtldVendLedger.[Entry Type] = 2
AND DtldVendLedger.[Initial Document Type] = 2
AND GLEntry.[Source Code] = 'PURCHASES'
AND GLEntry.[G_L Account No_] NOT IN ('2003','1402','1403','1401');
SET #inputtax = 0.12 * #vatable;

SQL Alternative to IN operator with variable and between

I'm trying to put some variables to an IN Operator but unfortunately it's not working. (found some articles on the internet about it). So what can I do?
I have some stacked queries combined to one. But then I have several times the same argument, well that's no problem. But I have to change all the arguments every times I want to make a new search. So to make it easy I used variables at the top of the query so I can't forget even one to change. And that's working also except for the IN operator. Somehow you can't use multiple variables with the IN operator except when using Dynamic SQL.
Now I have:
where [Item No_] not in ('0000900','00009900','00009906')
to exclude the products I don't want to see. At this moment there are only 3 but it have to be more, about 20 single once and some are in a range like 00005100 - 00007500 (yes that are 2400). (and in the next query I just need those 2400)
So I tried to Declare #Exception, but that's not working. Now I wonder if there is a way to make it work. If not with a variable then at least a combination of a IN and between statement. Or some other way around.
And here is the whole query. I commented out the #Exception variable:
Declare #Start datetime = '01.04.2015',
#Ende datetime = '30.04.2015';
/* #Ausnahme ;
Insert #Ausnahme values (00009000),(00009900),(00009906);
*/
SELECT t1.[Location Code], CAST(t1.Umsatz as DECIMAL(18,2))as Umsatz , CAST(COALESCE(t2.Ersatznachweis, 0) as DECIMAL(18,2)) as Ersatznachweis, CAST(T5.Rückgabe as Decimal(18,2)) as Rückgabe
FROM (
SELECT [Location Code], SUM(WareBrutto) AS Umsatz
FROM (SELECT DISTINCT [Location Code], [Document No_] , WareBrutto from [Item Ledger Entry]
WHERE [Location Code] between '0000' and '0040' and [Document Date] between #Start and #Ende) t
GROUP BY [Location Code]) as t1
LEFT JOIN
(select [Location Code], sum([Quantity]*Bruttopreis) as Ersatznachweis from [Item Ledger Entry]
where [Location Code] between '0000' and '0040' and [Item No_] not IN ('00009000','00009900','00009906') and Gutschrift = '1' and [Document Date] between #Start and #Ende
Group By [Location Code]) as t2
on t1.[Location Code] = t2.[Location Code]
Left JOIN
(Select [Location Code], sum(Quantity*PR_Brutto*-1) As Rückgabe
From (
select [Location Code], [Item No_], [Quantity] from [Item Ledger Entry]
where [Location Code] between '0000' and '0040' and [Item No_] not in ('00009000','00009900','00009906') and Rückgabe = '1' and [Document Date] between #Start and #Ende ) as T3
Left Join
(Select ARTNR, PR_Brutto from dep_prs
where LIdx = '4' and Preisgruppe = '1') as T4 ON T3.[Item No_] = T4.ARTNR
Group By T3.[Location Code]) as T5 on t1.[Location Code] = T5.[Location Code]
Order by t1.[Location Code]
You can declare a table variable (or parameter if it's a part of a procedure or function) and use it for the not in part:
DECLARE #NotIn table (
NotInValues int
)
INSERT INTO #NotIn Values
('00009000'),
('00009900'),
('00009906')
and use it in your code like this:
where [Location Code] between '0000' and '0040'
and [Item No_] not IN (select NotInValues from #NotIn)
and Gutschrift = '1'
and [Document Date] between #Start and #Ende
Note #1: for a large number of values, not exists will probably perform better then not in
Note #2: If it's a part of a stored procedure you will need to create a user defined table type, and use it to declare the table valued parameter. Also, table valued parameters are readonly, so performing DML statements (insert/update/delete) on them will raise an error.
To create the udt:
CREATE TYPE IntegerList As Table
(
IntValue int
)
To declare it in the stored procedure parameters list:
CREATE PROCEDURE procedureName
(
#IntList dbo.IntegerList READONLY
-- Note that the readonly must be a part of the parameter declaration.
)