sql print duplicate value only one time - sql-server

i have a table like the following
bill_id sonvinid tid date brandname
1000109201701 13413 1 2015-10-03 00:00:00.000 QED - TM
1000109201701 13741 1 2015-10-13 00:00:00.000 QED - TM
1000109201702 14258 1 2015-11-05 00:00:00.000 QED - TM
now i want to run a query in which bill_id should not repeat, and repeated column with same bill_id should be shown as null
bill_id sonvinid tid date brandname
1000109201701 13413 1 2015-10-03 00:00:00.000 QED - TM
13741 1 2015-10-13 00:00:00.000 QED - TM
1000109201702 14258 1 2015-11-05 00:00:00.000 QED - TM
i know i can't use distinct here
then, what query will be the best to run this type of select command?

SELECT CASE WHEN row_num = 1 THEN bill_id ELSE NULL END AS bill_id
, sonvinid
, tid
, date
, brandname
FROM
( SELECT bill_id
, ROW_NUMBER() OVER (PARTITION BY bill_id ORDER BY date ASC) row_num
, sonvinid
, tid
, date
, brandname
FROM table1
) a;
Anyway I agree with the Sean's comment, that this is supposed to be done on UI side

Related

How to pivot wider these dataset

My test dataset
IdCx FecCx OrderId Value
1234 2022-08-15 1 07:50
1234 2022-08-15 2 08:00
1234 2022-08-15 3 08:24
5678 2022-08-16 1 14:45
5678 2022-08-16 3 15:30
I require to pivot wider based on OrderId and Value
My expected result will look like (I do need the NULL in Val2)
IdCx FecCx Val1 Val2 Val3
1234 2022-08-15 07:50 08:00 08:24
5678 2022-08-16 14:45 NULL 15:30
My first approach has been with CASE but resulting dataset will not coalesce rows, leaving a lot of undesired nulls
My dbFiddle
You simply need to aggregate - this collapses your NULL values into one row per group:
select idCx, FecCx
,max(case when OrderId = 1 then Value end) as Val1
,max(case when OrderId = 2 then Value end) as Val2
,max(case when OrderId = 3 then Value end) as Val3
from dbo.fact1
group by idCx, FecCx;
See modified Fiddle
Just in case ORderID is not sequential, we use the window function row_number() over() in concert with a PIVOT
Example or dbFiddle
Select *
From (
Select IDcx
,FecCx
,Item = concat('Val',row_number() over (partition by idcx,FecCx order by OrderID) )
,Value
From fact1
) src
Pivot ( max(Value) for Item in ([Val1],[Val2],[Val3])) pvt

13 Period Calendar 4-4-5 Calendar T-SQL MSSQL

I am trying to create a 13 period calendar in mssql but I am a bit stuck. I am not sure if my approach is the best way to achieve this. I have my base script which can be seen below:
Set DateFirst 1
Declare #Date1 date = '20180101' --startdate should always be start of
financial year
Declare #Date2 date = '20181231' --enddate should always be start of
financial year
SELECT * INTO #CalendarTable
FROM dbo.CalendarTable(#Date1,#Date2,0,0,0)c
DECLARE #StartDate datetime,#EndDate datetime
SELECT #StartDate=MIN(CASE WHEN [Day]='Monday' THEN [Date] ELSE NULL END),
#EndDate=MAX([Date])
FROM #CalendarTable
;With Period_CTE(PeriodNo,Start,[End])
AS
(SELECT 1,#StartDate,DATEADD(wk,4,#StartDate) -1
UNION ALL
SELECT PeriodNo+1,DATEADD(wk,4,Start),DATEADD(wk,4,[End])
FROM Period_CTE
WHERE DATEADD(wk,4,[End])< =#EndDate
OR PeriodNo+1 <=13
)
select * from Period_CTE
Which gives me this:
PeriodNo Start End
1 2018-01-01 00:00:00.000 2018-01-28 00:00:00.000
2 2018-01-29 00:00:00.000 2018-02-25 00:00:00.000
3 2018-02-26 00:00:00.000 2018-03-25 00:00:00.000
4 2018-03-26 00:00:00.000 2018-04-22 00:00:00.000
5 2018-04-23 00:00:00.000 2018-05-20 00:00:00.000
6 2018-05-21 00:00:00.000 2018-06-17 00:00:00.000
7 2018-06-18 00:00:00.000 2018-07-15 00:00:00.000
8 2018-07-16 00:00:00.000 2018-08-12 00:00:00.000
9 2018-08-13 00:00:00.000 2018-09-09 00:00:00.000
10 2018-09-10 00:00:00.000 2018-10-07 00:00:00.000
11 2018-10-08 00:00:00.000 2018-11-04 00:00:00.000
12 2018-11-05 00:00:00.000 2018-12-02 00:00:00.000
13 2018-12-03 00:00:00.000 2018-12-30 00:00:00.000
The result i am trying to get is
Even if I have to take a different approach I would not mind, as long as the result is the same as the above.
dbo.CalendarTable() is a function that returns the following results. I can share the code if desired.
I'd create a general number's table like suggested here and add a column Periode13.
The trick to get the tiling is the integer division:
DECLARE #PeriodeSize INT=28; --13 "moon-months" a 28 days
SELECT TOP 100 (ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1)/#PeriodeSize
FROM master..spt_values --just a table with many rows to show the principles
You can add this to an existing numbers table with a simple update statement.
UPDATE A fully working example (using the logic linked above)
DECLARE #RunningNumbers TABLE (Number INT NOT NULL
,CalendarDate DATE NOT NULL
,CalendarYear INT NOT NULL
,CalendarMonth INT NOT NULL
,CalendarDay INT NOT NULL
,CalendarWeek INT NOT NULL
,CalendarYearDay INT NOT NULL
,CalendarWeekDay INT NOT NULL);
DECLARE #CountEntries INT = 100000;
DECLARE #StartNumber INT = 0;
WITH E1(N) AS(SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)), --10 ^ 1
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
CteTally AS
(
SELECT TOP(ISNULL(#CountEntries,1000000)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) -1 + ISNULL(#StartNumber,0) As Nmbr
FROM E8
)
INSERT INTO #RunningNumbers
SELECT CteTally.Nmbr,CalendarDate.d,CalendarExt.*
FROM CteTally
CROSS APPLY
(
SELECT DATEADD(DAY,CteTally.Nmbr,{ts'2018-01-01 00:00:00'})
) AS CalendarDate(d)
CROSS APPLY
(
SELECT YEAR(CalendarDate.d) AS CalendarYear
,MONTH(CalendarDate.d) AS CalendarMonth
,DAY(CalendarDate.d) AS CalendarDay
,DATEPART(WEEK,CalendarDate.d) AS CalendarWeek
,DATEPART(DAYOFYEAR,CalendarDate.d) AS CalendarYearDay
,DATEPART(WEEKDAY,CalendarDate.d) AS CalendarWeekDay
) AS CalendarExt;
--The mockup table from above is now filled and can be queried
WITH AddPeriode AS
(
SELECT Number/28 +1 AS PeriodNumber
,CalendarDate
,CalendarWeek
,r.CalendarDay
,r.CalendarMonth
,r.CalendarWeekDay
,r.CalendarYear
,r.CalendarYearDay
FROM #RunningNumbers AS r
)
SELECT TOP 100 p.*
,(SELECT MIN(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber) AS [Start]
,(SELECT MAX(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber) AS [End]
,(SELECT MIN(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber AND x.CalendarWeek=p.CalendarWeek) AS [wkStart]
,(SELECT MAX(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber AND x.CalendarWeek=p.CalendarWeek) AS [wkEnd]
,(ROW_NUMBER() OVER(PARTITION BY PeriodNumber ORDER BY CalendarDate)-1)/7+1 AS WeekOfPeriode
FROM AddPeriode AS p
ORDER BY CalendarDate
Try it out...
Hint: Do not use a VIEW or iTVF for this.
This is non-changing data and much better placed in a physically stored table with appropriate indexes.
Not abundantly sure external links are accepted here, but I wrote an article that pulls of a 5-4-4 'Crop Year' fiscal year with all the code. Feel free to use all the code in these articles.
SQL Server Calendar Table
SQL Server Calendar Table: Fiscal Years

IF statment in SQL

I have a table_changes (Id,stard_date,end_date) and I want to add two columns rank_end_date and new_end_date.
The problem I have in my data is that not always there is continuousness (in the month level, the day in the month is not in my intrest) between end_date and the start_date coming just after it (see example 1) so I need to "strech" end_date in some cases so there will be continuousness at the level of the month.
For example 1, the new_end_date is 1/2/2015 and doesn't have to be 28/2/2015. If the end_date in rank 1 is sooner than 31/12/2015 strech it to 31/12/9999.
Some Examples:
Ex1:
Id --start date --end_date --rank_end_date new_end_date
111 01/01/1970 1/1/1980 2 1/2/2015
111 01/03/2015 31/12/9999 1 31/12/9999
Ex2:
Id --start_date --end_date --rank_end_date new_end_date
111 01/01/1970 1/1/1980 1 31/12/9999
Ex3:
Id --start_date --end_date --rank_end_date new_end_date
111 01/01/1970 1/1/1980 2 01/05/1990
111 01/05/1990 31/12/1995 1 31/12/9999
Ex4:
Id --start_date --end_date --rank__end_date new_end_date
111 01/03/2015 31/12/9999 1 31/12/9999
Ex5:
Id --start_Date --end_date --rank__end_date new_end_date
111 01/02/2015 31/5/2015 2 01/5/2015
111 01/06/2015 31/12/9999 1 31/12/9999
the syntax should be something like this but I don't know how to write those IF statements in SQL:
if rank_end_date ==2 then new_end_date == 1/Month(start_date(rank_end_date - 1)) - 1 /2015
if rank_end_date ==1 then new_end_date == 31/12/2015
else new_end_date = end_date
Select [Id],[StartDate],[EndDate],
Rank_End_Date, case
when t.Rank_End_Date = (2) **then
CAST(CAST(Year([StartDate]) AS varchar) + '-' + CAST(Month([StartDate]) AS varchar) + '-' +
--How to do I choose the Start_Date from the record with Rank==1? It is selecting
the start date from the record with rank==2 ofcourse.
CAST(Day ([EMER_StartDate]) AS varchar) AS DATE)
when t.Rank_End_Date = (1) then '9999-12-31'
else t.[EMER_EndDate] end As New_End_Date
from (
Select [Id],[StartDate],[EndDate],
Rank() OVER (PARTITION BY [Id] order by [EndDate] desc) as Rank_End_Date
from [dbo].[Changes]
) t
Could anybody help in achieving the result?
If I've understood your question right, and you can only have values in rank_end_date of 1 or 2 then something like this query should give you the answer you're looking for. Either way, the LEAD (or LAG function if you sort the records ascending) will allow you to fetch the value from a different record.
SELECT ID
, start_date
, end_date
, rank_end_date
, CASE WHEN rank_end_date = 1 THEN
CASE WHEN end_date < '31/12/2005' THEN '31/12/9999' ELSE end_date END
WHEN rank_end_date = 2 THEN LEAD(start_date,1) OVER(ORDER BY ID, rank_end_date DESC)
END AS new_end_date
FROM dbo.Changes
You can't use LEAD OR LAG functions in SQL Server 2008, so you can try this solution.
with CTE as
(
Select [Id] as ID,[StartDate] as StartDate,[EndDate] as EndDate,
ROW_NUMBER() OVER (PARTITION BY [Id] order by [StartDate] DESC) as rn_Start_Date
from [dbo].[Changes]
)
Select C1.[Id] , C1.[StartDate], C1.[EndDate], C1.rn_Start_Date as Rank_end_date,
ISNULL(DATEADD(MONTH, DATEDIFF(MONTH, 0, C2.[StartDate])-1, 0), cast('9999-12-31' as DATE)) As New_End_Date
From CTE C1
LEFT JOIN CTE C2 ON C1.[ID] = C2.[ID] AND C1.Rn_Start_Date = C2.Rn_Start_Date + 1

Fetching dates monthly from the table

Can you help out with a problem
I have table price table which has daily prices starting 31st Dec 2010 till todays date.The table contains daily prices
2009-12-31 00:00:00.000 1.0020945351
2010-01-01 00:00:00.000 1.0021009300
2010-01-04 00:00:00.000 1.0021910181
2010-01-05 00:00:00.000 1.0022005986
2010-01-06 00:00:00.000 1.0022428696
2010-01-07 00:00:00.000 1.0022647147
2010-01-08 00:00:00.000 1.0022842726
2010-01-11 00:00:00.000 1.0023374302
2010-01-12 00:00:00.000 1.0023465374
2010-01-13 00:00:00.000 1.0023638081
2010-01-14 00:00:00.000 1.0023856533
2010-01-00 00:00:00.000 1.0024083955
2010-01-18 00:00:00.000 1.0024779677
2010-01-19 00:00:00.000 1.0025020553
2010-01-20 00:00:00.000 1.002521135
2010-01-21 00:00:00.000 1.0025420688
2010-01-22 00:00:00.000 1.0025593397
2010-01-25 00:00:00.000 1.0026180146
2010-01-26 00:00:00.000 1.002637573
2010-01-27 00:00:00.000 1.0026648447
2010-01-28 00:00:00.000 1.0026957934
2010-01-29 00:00:00.000 1.0027267421
2010-02-01 00:00:00.000 1.0028195885
2010-02-02 00:00:00.000 1.0028573523
2010-02-03 00:00:00.000 1.0028964611
2010-02-04 00:00:00.000 1.00293557
2010-02-05 00:00:00.000 1.002973334
2010-02-08 00:00:00.000 1.0030879717
2010-02-09 00:00:00.000 1.0031279777
2010-02-10 00:00:00.000 1.003171166
2010-02-11 00:00:00.000 1.0032007452
2010-02-12 00:00:00.000 1.0032575895
2010-02-00 00:00:00.000 1.0033749191
2010-02-1 00:00:00.000 1.0034140292
2010-02-17 00:00:00.000 1.003452691
2010-02-18 00:00:00.000 1.0034918013
2010-02-19 00:00:00.000 1.0035395633
2010-02-22 00:00:00.000 1.0036664439
2010-02-23 00:00:00.000 1.0037042097
2010-02-24 00:00:00.000 1.0037510759
2010-02-25 00:00:00.000 1.0038001834
2010-02-26 00:00:00.000 1.003850077
I need to write a query to get index based on
(Last day of current month/Previous month last day) - 1 * 100.So that output comes something like this
31-Jan-10 0.01%
28-Feb-10 0.02%
31-Mar-10 0.00%
Following is one of the solution I thought about however please share best ideas to implement this problem
Extract last day of all the months with values into a temp table and then order by dates so that they subtract and put the values into another temp table
Looking forward to your help.
Try this....
DECLARE #StartDate DATETIME = '2010-01-01',
#EndDate DATETIME = GETDATE();
WITH data AS (
SELECT 1 AS i, CONVERT(DATETIME, NULL) AS StartDate, DATEADD(MONTH, 0, #StartDate) - 1 AS EndDate
UNION ALL
SELECT i + 1, data.EndDate, DATEADD(MONTH, i, #StartDate) - 1 AS EndDate
FROM data
WHERE DATEADD(MONTH, i, #StartDate) - 1 < #EndDate
)
SELECT (
((SELECT TOP 1 Rate FROM RateTable WHERE Date <= data.EndDate ORDER BY Date DESC) /
(SELECT TOP 1 Rate FROM RateTable WHERE Date <= data.StartDate ORDER BY Date DESC)- 1) * 100)
FROM DATA -- parenthesis were causing issues
WHERE data.StartDate IS NOT NULL
OPTION (MAXRECURSION 10000);
You'll need to replace the
(SELECT Rate FROM RateTable WHERE Date = data.StartDate)
and
(SELECT Rate FROM RateTable WHERE Date = data.EndDate)
With the values for your rate table. as you didn't mention column and table names in your question.
rwking indicated that there might be gaps in the rates table that would cause issues.
I've modified the subquery to bring back the first rate on or nearest the start and end dates.
Hope that helps
You can use the LAG function introduced in SQL2012 to make it a bit easier:
WITH DataWithOrder AS
(
SELECT DateField, PriceField,
ROW_NUMBER() OVER(PARTITION BY YEAR(DateField), Month(DateField) ORDER BY DateField DESC) AS Pos
FROM PriceTable
)
SELECT
DateField,
PriceField,
LAG(PriceField) OVER(ORDER BY DateField) AS PriceLastMonth,
((PriceField / LAG(PriceField) OVER(ORDER BY DateField)) - 1) * 100 AS PCIncrease
FROM DataWithOrder
WHERE Pos = 1
ORDER BY DateField
I took a very different approach than the other guy. His is more elegant and would work better if the daily data does represent every single day of every month. If there are gaps in days, however, as your sample data represents, you can try the following code.
with cte as (select mydate
, price
, ROW_NUMBER() over(partition by YEAR(mydate), MONTH(mydate)
order by day(mydate) desc) row_n
from #temp)
select mydate, price, ROW_NUMBER() over(order by mydate desc) row_num
into #temp2
from cte
where row_n = 1
alter table #temp2
add idx float
declare #counter int = 1
while #counter < (select MAX(row_num)+1 from #temp2)
begin
update t2
set t2.idx = ((t2.price/t3.price)-1)*100
from #temp2 t2 left join
#temp2 t3 on 1 = 1
where t2.row_num = #counter and t3.row_num = #counter + 1
set #counter = #counter + 1
end
select mydate, idx
from #temp2
As the other poster mentioned, you didn't provide column or table names. My process was to insert your data into a table called [#temp] with column names [mydate] and [price].
Also, the data sample you provided contains two invalid dates that I changed to arbitrary dates just for the purposes of getting code to run. (2010-01-00 and 2010-02-00)

Calculate total running time from start/stop timestamps

I have a table containing a number of timestamps per day, they represents start and stop events.
ID TimeStamp
----------------------
1 2008-01-01 07:00:00
1 2008-01-01 08:15:00
1 2008-01-01 10:00:00
1 2008-01-01 11:00:00
1 2008-01-02 10:30:00
1 2008-01-02 12:00:00
I would like to calcuate the total running time per day, like this:
ID Date RunningTime
-------------------------
1 2008-01-01 02:15:00
1 2008-01-02 01:30:00
Do anyone have a nice T-SQL solution for my problem?
WITH q AS
(
SELECT *,
CONVERT(DATETIME, CONVERT(VARCHAR(8), TimeStamp, 112), 112) AS dte,
ROW_NUMBER() OVER (PARTITION BY id, CONVERT(DATETIME, CONVERT(VARCHAR(8), TimeStamp, 112), 112) ORDER BY TimeStamp) AS rn
FROM mytable
)
SELECT qb.id, qb.dte, SUM(DATEDIFF(second, qb.TimeStamp, qe.TimeStamp))
FROM q qb
JOIN q qe
ON qe.id = qb.id
AND qe.dte = qb.dte
AND qe.rn = qb.rn + 1
WHERE qb.rn % 2 = 1
GROUP BY
qb.id, qb.dte
This assumes that every record open on a certain day should also be closed on the same day.

Resources