Want Result from one to many relation table by Group By - sql-server

I would like to get result by "group by" but not luck. I can see other option but looking best perfomance query.
Thanks in Advance !
CREATE TABLE #Invoice (InvoiceId int, InvoiceDate datetime, NetAmount
decimal(18,2))
CREATE TABLE #Payment (PaymentId int, InvoiceId int, PaidAmount
decimal(18,2))
INSERT INTO #Invoice VALUES (101, '20180212', 5000)
INSERT INTO #Invoice VALUES (102, '20180112', 600)
INSERT INTO #Invoice VALUES (103, '20181211', 1800)
INSERT INTO #Invoice VALUES (104, '20180101', 1000)
INSERT INTO #Invoice VALUES (105, '20180212', 7000)
INSERT INTO #Payment VALUES (101,103,1800)
INSERT INTO #Payment VALUES (102,102,500)
INSERT INTO #Payment VALUES (103,101,2000)
INSERT INTO #Payment VALUES (103,101,3000)
Create this query :
SELECT
INV.InvoiceDate,
SUM(Inv.NetAmount) as NetAmount,
SUM(ISNULL(PY.PaidAmount,0)) As PaidAmount
From #Invoice INV
LEFT JOIN #Payment PY
ON PY.InvoiceId = INV.InvoiceId
GROUP BY
INV.InvoiceDate
Get Result :
InvoiceDate NetAmount PaidAmount
2018-01-01 1000.00 0.00
2018-01-12 600.00 500.00
2018-02-12 17000.00 5000.00 ****Issue: Net values should be 12000 not 17000
2018-12-11 1800.00 1800.00
Expected Result :
InvoiceDate NetAmount PaidAmount
2018-01-01 1000.00 0.00
2018-01-12 600.00 500.00
2018-02-12 5000.00 5000.00
2018-12-11 1800.00 1800.00

This assumes that the expected results the OP has provided is wrong. They have the value 5000 for the NetAmount on 20180212, however there are 2 invoices on that date with the values 5000 and 7000, making 12000. If 5000 is correct, we need details on why the value of invoice 105 (7000) is not to be included.
Anyway, on the assumption the expected results is wrong, this gets the result I believe you are looking for:
WITH CTE AS(
SELECT I.InvoiceId,
I.InvoiceDate,
I.NetAmount,
P.PaymentId,
P.PaidAmount,
ROW_NUMBER() OVER (PARTITION BY I.InvoiceId, I.InvoiceDate ORDER BY (SELECT NULL)) AS RN
FROM #Invoice I
LEFT JOIN #Payment P ON I.InvoiceId = P.InvoiceId)
SELECT C.InvoiceDate,
SUM(CASE RN WHEN 1 THEN C.NetAmount END) AS NetAmount,
ISNULL(SUM(C.PaidAmount),0) AS PaidAmount
FROM CTE C
GROUP BY C.InvoiceDate;

Related

How do i select the free time between start time and end time in sql?

I want to select all the free time other that the mentioned ones for which the room is free.
eg table:
room starttime endtime date
1 | 12pm | 1pm | 2018-02-18 00:00:00.000
1 | 2pm | 3pm | 2018-02-18 00:00:00.000
1 | 3pm | 5pm | 2018-02-18 00:00:00.000
expected output eg:
freetime
6-12,5-10
Is this even possible?
Thanks in advance.
This is for a assignment where the room is booked for a class for particular starttime(date) and endtime(date) and date.
I need to find out the times when the class will be free.
Above free timings was just an example.
Possible solution:
set dateformat ymd
-- Sample data
declare #MyTable
table (room varchar(1), starttime varchar(4), endtime varchar(4), [date] datetime)
insert into #MyTable values ('1', '12pm', '1pm', '2018-02-18 00:00:00.000')
insert into #MyTable values ('1', '2pm', '3pm', '2018-02-18 00:00:00.000')
insert into #MyTable values ('1', '3pm', '5pm', '2018-02-18 00:00:00.000')
select d.[date], r.room, t.freehour
from
(select cast(dateadd(hour, number, 0) as time) as freehour
from master..spt_values where type = 'P' and number between 6 and 22) t,
(select distinct room from #MyTable) r,
(select distinct [date] as [date] from #MyTable) d
where not exists (
select 1
from #MyTable m
where m.[date] = d.[date]
and m.room = r.room
and t.freehour between cast(m.starttime as time)
and dateadd(hour,-1,cast(m.endtime as time))
)

How do I add original amount of oldest transaction in an aggregate function?

I'm trying to find out how to include the original amount of the first transaction (oldest by Posted Date) to an aggregate query.
The following finds reversed transactions ..
SELECT DISTINCT
[Account], [Voucher],
[DocumentDate],
SUM([Amount])
FROM
MyTable
WHERE
[Account] = 'abc'
GROUP BY
[Account], [Voucher], [DocumentDate]
HAVING
SUM([Amount]) = 0
How would I include the amount in the results for the transaction with the oldest posted date for each record?
For example, using the following:
Account Voucher DocumentDate PostedDate Amount
---------------------------------------------------------
abc 1 01/01/2018 08/01/2018 100.00
abc 1 01/01/2018 15/01/2018 -100.00
The expected result would be:
Account Voucher DocumentDate OriginalAmount Sum(Amount) Records
-------------------------------------------------------------------------
abc 1 01/01/2018 100.00 0.00 2
One way to do it is using a cte with first_value, sum...over and count...over.
First, create and populate sample table (Please save us this step in your future questions)
DECLARE #T AS TABLE
(
Account char(3),
Voucher int,
DocumentDate date,
PostedDate date,
Amount numeric(5,2)
)
INSERT INTO #T VALUES
('abc', 1, '2018-01-01', '2018-01-08', 100),
('abc', 1, '2018-01-01', '2018-01-15', -100)
The cte:
;WITH CTE
AS
(
SELECT [Account],
[Voucher],
[DocumentDate],
FIRST_VALUE(Amount) OVER(PARTITION BY [Account], [Voucher], [DocumentDate] ORDER BY PostedDate) AS OriginalAmount,
SUM([Amount]) OVER(PARTITION BY [Account], [Voucher], [DocumentDate]) AS [Sum(Amount)],
COUNT(*) OVER(PARTITION BY [Account], [Voucher], [DocumentDate]) Records
FROM
#T
WHERE
[Account] = 'abc'
)
The query:
SELECT DISTINCT *
FROM CTE
WHERE [Sum(Amount)] = 0
Results:
Account Voucher DocumentDate OriginalAmount Sum(Amount) Records
abc 1 01.01.2018 00:00:00 100,00 0,00 2
See a live demo on rextester.
It seems straightforward ... am I missing something?
WITH CTE AS
(
SELECT
[Account],
[Voucher],
[DocumentDate],
ROW_NUMBER() OVER (PARTITION BY [Account],[Voucher] ORDER BY [DocumentDate]) RN,
[Amount]
FROM
MyTable
WHERE
[Account] = 'abc'
)
SELECT
[Account],
[Voucher],
[DocumentDate],
max(case when RN = 1 THEN [Amount] else null end) OriginalAmount,
sum([Amount]) SUM_Amount,
count(*) Records
from cte
GROUP BY
[Account], [Voucher], [DocumentDate]
HAVING
SUM([Amount]) = 0

Retrieve column based on closest date

Thanks for your help in advance. I have an invoice table which is similar to below:
INV DATE | ITEM |SELL PRICE |COST PRICE
------------+-------+-----------+----------
30/06/2016 | DOOR1 |10 |5
The above item is sourced from the EU so I have another table (VEN_HIS) which lists a history of supplier prices for that item as below:
DATE |ITEM |CURRENCY |PRICE
------------+-------+-----------+------
17/05/2017 |DOOR1 |EUR |6
01/01/2017 |DOOR1 |EUR |5.8
29/05/2016 |DOOR1 |EUR |5.6
05/03/2016 |DOOR1 |EUR |5.5
What I want to do is join the tables to drop in the correct currency price we would have paid onto the invoice table as at the invoice date in other words the correct price is 5.6
This is my first post and I need to get some FX analysis done quickly so apologies for the formatting, any help would be greatly appreciated.
Its a simple question of Join and where clause.
create table #t1 (INV_DATE DATE,ITEM varchar(100), SELL_PRICE int, COST_PRICE int);
insert into #t1 values
('30/06/2016','DOOR1',10,5)
create table #ven_his (colDATE date, ITEM varchar(100), CURRENCY varchar(100),PRICE float);
insert into #ven_his values
('17/05/2017', 'DOOR1', 'EUR',6 ),
('01/01/2017', 'DOOR1', 'EUR',5.8),
('29/05/2016', 'DOOR1', 'EUR',5.6),
('05/03/2016', 'DOOR1', 'EUR',5.5)
SELECT top 1 a.INV_DATE, a.ITEM, b.CURRENCY, b.PRICE
FROM #t1 a
left join #ven_his b
on a.ITEM = b.ITEM
WHERE b.colDATE <=a.INV_DATE
ORDER BY b.colDATE DESC
output :
#t1
INV_DATE ITEM SELL_PRICE COST_PRICE
---------- ------ ----------- -----------
2016-06-30 DOOR1 10 5
#ven_his
colDATE ITEM CURRENCY PRICE
---------- --------- ------------ ------
2017-05-17 DOOR1 EUR 6
2017-01-01 DOOR1 EUR 5.8
2016-05-29 DOOR1 EUR 5.6
2016-03-05 DOOR1 EUR 5.5
INV_DATE ITEM CURRENCY PRICE
---------- --------- ----------- --------
2016-06-30 DOOR1 EUR 5.6
DECLARE #invoice table (INV_Date date, Item varchar(100),SellPrice numeric(5,2), Costprice numeric(5,2))
INSERT INTO #invoice
SELECT '20160630','DOOR1',10,5
SELECT * FrOm #invoice
DECLARE #ven_his table(Dates date,Item varchar(100),Currency varchar(10),Price numeric(5,2))
INSERT INTO #ven_his
SELECT '20170517','DOOR1','EUR',6
UNION ALL
SELECT '20170101','DOOR1','EUR',5.8
UNION ALL
SELECT '20160529','DOOR1','EUR',5.6
UNION ALL
SELECT '20160305','DOOR1','EUR',5.5
SELECT * FROM #ven_his
SELECT Top 1 i.Item,INV_Date,PRICE,Dates
FROM #invoice i
JOIN #ven_his v
ON i.Item = v.Item
ORDER BY ABS(DATEDIFF(DAY,i.INV_Date,v.Dates))
Use LEAD function to return the correct price for all items:
Create table #Invoice (INVDATE DATE, ITEM NVARCHAR(20), SELLPRICE SMALLMONEY, COSTPRICE SMALLMONEY)
INSERT #INVOICE VALUES ('2016-06-30', 'DOOR1', 10, 5)
--Test with additional invoices
--INSERT #INVOICE VALUES ('2017-02-22', 'DOOR1', 10, 5), ('2016-09-22', 'DOOR1', 10, 5)
CREATE TABLE #VENHIS ([DATE] DATE, ITEM NVARCHAR(20), CURRENCY NVARCHAR(5), PRICE SMALLMONEY)
INSERT #VENHIS VALUES ('2017-05-17', 'DOOR1', 'EUR', 6), ('2017-01-01', 'DOOR1', 'EUR', 5.8),('2016-05-29', 'DOOR1', 'EUR', 5.6), ('2016-03-05', 'DOOR1', 'EUR', 5.5)
SELECT I.*, V.PRICE
FROM #Invoice i
INNER JOIN (SELECT *, [DATE] as STARTDATE, LEAD([DATE]) OVER (PARTITION BY ITEM ORDER BY ITEM, [DATE] ASC) AS EndDate
FROM #VENHIS ) v ON i.ITEM=v.ITEM AND I.[INVDATE] BETWEEN V.STARTDATE AND DATEADD(D,-1,ISNULL(V.ENDDATE, '2099-01-01'))

JOIN on multilple rows to SELECT only TOP row in SQL Sever

I have a table which has only 1 row per ID/Date while the other one can have overlapping ID/Dates. I need to JOIN them in such a way that only top row is selected (actually any row from duplicates table is fine!). Its fairly easy to do this in 2 steps (Insert & Update) but I'm looking if it can be done in a single step.
CREATE TABLE #Row1Each (ID VARCHAR(10), Date_ DATETIME, Value FLOAT) INSERT INTO #Row1Each SELECT 'AAPL', '1/10/2015', 100 INSERT INTO #Row1Each SELECT 'MSFT', '1/10/2015', 20
CREATE TABLE #Table1 (ID VARCHAR(10), Date_ DATETIME, Qty FLOAT) INSERT INTO #Table1 SELECT 'AAPL', '1/10/2015', 55000
CREATE TABLE #Duplicates (ID VARCHAR(10), StartDate DATETIME, EndDate DATETIME, Quote FLOAT) INSERT INTO #Duplicates SELECT 'AAPL', '1/2/2015', '12/31/2016', 0.1 INSERT INTO #Duplicates SELECT 'AAPL', '1/4/2015', '10/05/2016', 0.11
/*
AAPL 2015-01-10 00:00:00.000 100
MSFT 2015-01-10 00:00:00.000 20
AAPL 2015-01-10 00:00:00.000 55000
AAPL 2015-01-02 00:00:00.000 2016-12-31 00:00:00.000 0.1
AAPL 2015-01-04 00:00:00.000 2016-10-05 00:00:00.000 0.1
*/
SELECT A.*
, B.Qty
, C.Quote
FROM #Row1Each A
LEFT JOIN #Table1 B ON B.ID = A.ID
AND B.Date_ = A.Date_
LEFT JOIN #Duplicates C ON C.ID = A.ID
AND A.Date_ BETWEEN C.StartDate AND C.EndDate
DROP TABLE #Row1Each DROP TABLE #Table1 DROP TABLE #Duplicates
/* Desired output
AAPL 2015-01-10 00:00:00.000 100 55000 0.1
MSFT 2015-01-10 00:00:00.000 20 NULL NULL
*/
You can do this using APPLY.
SELECT
r.Id,
r.Date_,
r.Value,
t.Qty,
d.Quote
FROM #Row1Each r
LEFT JOIN #Table1 t
ON t.ID = r.ID
AND t.Date_ = r.Date_
OUTER APPLY(
SELECT TOP 1 *
FROM #Duplicates d
WHERE
d.ID = r.ID
AND r.Date_ BETWEEN d.StartDate AND d.EndDate
ORDER BY EndDate DESC -- Returns Top 1 Based on EndDate
)d

Date comparing between two dates? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Value should be 0 between the two dates?
SQL Server 2000
Table1
ID Date Workedtime
001 23-02-2009 08:00:00
001 24-02-2009 15:00:00
001 25-02-2009 17:00:00
002 ...
So on..,
Table2
ID FromDate ToDate
001 24-02-2009 25-02-2009
002 27-02-2009 03-03-2009
...
I want to compare the table1 date and ID with Table2 ID FromDate, ToDate, means
Table1 Date compare with FromDate ToDate, if Date is comes in between fromdate and todate, the worktime should display absent.
Expected Output
ID Date Workedtime
001 23-02-2009 08:00:00
001 24-02-2009 absent
001 25-02-2009 absent
002 ...
Need Query Help
This should help from what you have specified above
DECLARE #Table1 TABLE(
ID VARCHAR(10),
Date DATETIME,
Workedtime VARCHAR(10)
)
INSERT INTO #Table1 (ID,Date,Workedtime) SELECT '001', '23 Feb 2009', '08:00:00'
INSERT INTO #Table1 (ID,Date,Workedtime) SELECT '001', '24 Feb 2009', '15:00:00'
INSERT INTO #Table1 (ID,Date,Workedtime) SELECT '001', '25 Feb 2009', '17:00:00'
DECLARE #Table2 TABLE(
ID VARCHAR(10),
FromDate DATETIME,
ToDate DATETIME
)
INSERT INTO #Table2 (ID,FromDate,ToDate) SELECT '001', '24 Feb 2009', ' 25 Feb 2009'
SELECT t1.ID,
t1.Date,
CASE WHEN t2.ID IS NULL THEN t1.Workedtime ELSE 'absent' END Workedtime
FROM #Table1 t1 LEFT JOIN
#Table2 t2 ON t1.ID = t2.ID
AND t1.Date BETWEEN t2.FromDate AND t2.ToDate

Resources