Filling a complete line of rows with last_value() oracle - database

First of all I have this table.
CREATE TABLE tabla_1
(table_num NUMBER, amount NUMBER, first_name VARCHAR2(100), l_name VARCHAR2(100));
INSERT INTO tabla_1 (table_num, amount, first_name,l_name) VALUES (1,1,'Luis', 'Rosas');
INSERT INTO tabla_1 (table_num, amount, first_name,l_name) VALUES (1,1,'Carlos','Borolas');
INSERT INTO tabla_1 (table_num, amount, first_name,l_name) VALUES (1,2,'Elena','Zeta');
INSERT INTO tabla_1 (table_num, amount, first_name,l_name) VALUES (1,null,null,null);
INSERT INTO tabla_1 (table_num, amount, first_name,l_name) VALUES (2,null,null,null);
commit;
query result:
TABLE_NUM AMOUNT FIRST_NAME L_NAME
---------- ---------- ---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
1 1 Luis Rosas
1 1 Carlos Borolas
1 2 Elena Zeta
1 -1 'N/A' 'N/A'
2 -1 'N/A' 'N/A'
Expected result:
TABLE_NUM AMOUNT FIRST_NAME L_NAME
---------- ---------- ----------------------------------------------------------------------------- ---------------------------------------------------------------
1 1 Luis Rosas
1 1 Carlos Borolas
1 2 Elena Zeta
1 2 Elena Zeta
2 2 Elena Zeta
sorry for the Spanish table, English it's not my native language.
The question is:
Note: In the last rows I have 'N/A' this is because this values was already null inserted. (I can't insert null values on a table, at least I have to insert something -1 on null numbers and 'n/a' on null varchar2 ), This is already done with code.
2.- How I can replace this """null"""" values with the previous last not """""null"""" values known by the user?
3.- which is better last_value or LAG, and how I can use it? Is it possible to use lag or last value in a complete row?

NVL + LAST_VALUE might be one option:
SQL> select table_num,
2 nvl(amount, last_value(amount ignore nulls) over (order by table_num)) amount,
3 nvl(first_name, last_value(first_name ignore nulls) over (order by table_num)) first_name
4 from tabla_1;
TABLE_NUM AMOUNT FIRST_NAME
---------- ------ --------------------
1 1 Carlos
1 1 Luis
1 2 Elena
1 2 Elena
2 2 Elena
SQL>
If there aren't NULLs (as sample data suggest) but -1 and N/A, then use CASE:
select table_num,
case when amount = -1 then last_value(amount ignore nulls) over (order by table_num)
else amount
end amount,
--
case when first_name = 'N/A' then last_value(first_name ignore nulls) over (order by table_num)
else first_name
end first_name
from tabla_1

Related

Identifying changes over time

No doubt a similar question has come up before, but I haven't been able to locate it by searching...
I have a raw dataset with time series data including 'from' and 'to' date fields.
The problem is, when data is loaded, new records have been created ('to' date added to old record, new record 'from' load date) even where no values have changed.
I want to convert this to a table which just shows a row for each genuine change - and the from/ to dates reflecting this.
By way of example, the source data looks like this:
ID
Col1
Col2
Col3
From
To
Test1
1
1
1
01/01/2020
31/12/9999
Test2
1
2
3
01/01/2020
30/06/2020
Test2
1
2
3
01/07/2020
30/09/2020
Test2
3
2
1
01/10/2020
31/12/9999
The first two records for Test2 (rows 2 and 3) are essentially the same - there was no change when the second row was loaded on 01/07/2020. I want a single row for the period 01/01/2020 - 30/09/2020 for which there was no change:
ID
Col1
Col2
Col3
From
To
Test1
1
1
1
01/01/2020
31/12/9999
Test2
1
2
3
01/01/2020
30/09/2020
Test2
3
2
1
01/10/2020
31/12/9999
For this simplified example, I can achieve that by grouping by each column (apart from dates) and using the MIN from date/ MAX end date:
SELECT
ID, Col1, Col2, Col3, MIN(From) AS From, MAX(To) as TO
FROM TABLE
GROUP BY ID, Col1, Col2, Col3
However, this won't work if a value changes then subsequently changes back to what it was before eg
ID
Col1
Col2
Col3
From
To
Test1
1
1
1
01/01/2020
31/12/9999
Test2
1
2
3
01/01/2020
30/04/2020
Test2
1
2
3
01/05/2020
30/06/2020
Test2
3
2
1
01/07/2020
30/10/2020
Test2
1
2
3
01/11/2020
31/12/9999
Simply using MIN/ MAX in the code above would return this - so it looks like both sets of values were valid for the period from 01/07/2020 - 30/10/2020:
ID
Col1
Col2
Col3
From
To
Test1
1
1
1
01/01/2020
31/12/9999
Test2
1
2
3
01/01/2020
31/12/9999
Test2
3
2
1
01/07/2020
30/10/2020
Whereas actually the first set of values were valid before and after that period, but not during.
It should return a single row for instead of two for the period from 01/01/2020 - 30/06/2020 when there were no changes for this ID, but then another row for the period when the values were different, and then another row where it reverted to the initial values, but with a new From date.
ID
Col1
Col2
Col3
From
To
Test1
1
1
1
01/01/2020
31/12/9999
Test2
1
2
3
01/01/2020
30/06/2020
Test2
3
2
1
01/07/2020
30/10/2020
Test2
1
2
3
01/11/2020
31/12/9999
I'm struggling to conceptualise how to approach this.
I'm guessing I need to use LAG somehow but not sure how to apply it - eg rank everything in a staging table first, then use LAG to compare a concatenation of the whole row?
I'm sure I could find a fudged way eventually, but I've no doubt this problem has been solved many times before so hoping somebody can point me to a simpler/ neater solution than I'd inevitably come up with...
Advanced Gaps and Islands
I believe this is an advanced "gaps and islands" problem. Use that as a search term and you'll find plenty of literature on the subject. Only difference is normally only one column is being tracked, but you have 3.
No Gaps Assumption
One major assumption of this script is there is no gap in the overlapping dates, or in other words, it assumes the previous rows ToDate = current FromDate - 1 day.
Not sure if you need to account for gaps, would be simple just add criteria to IsChanged to check for that
Multi-Column Gaps and Islands Solution
DROP TABLE IF EXISTS #Grouping
DROP TABLE IF EXISTS #Test
CREATE TABLE #Test (ID INT IDENTITY(1,1),TestName Varchar(10),Col1 INT,Col2 INT,Col3 INT,FromDate Date,ToDate DATE)
INSERT INTO #Test VALUES
('Test1',1,1,1,'2020-01-01','9999-12-31')
,('Test2',1,2,3,'2020-01-01','2020-04-30')
,('Test2',1,2,3,'2020-05-01','2020-06-30')
,('Test2',3,2,1,'2020-07-01','2020-10-30')
,('Test2',1,2,3,'2020-11-01','9999-12-31')
;WITH cte_Prev AS (
SELECT *
,PrevCol1 = LAG(Col1) OVER (PARTITION BY TestName ORDER BY FromDate)
,PrevCol2 = LAG(Col2) OVER (PARTITION BY TestName ORDER BY FromDate)
,PrevCol3 = LAG(Col3) OVER (PARTITION BY TestName ORDER BY FromDate)
FROM #Test
), cte_Compare AS (
SELECT *
,IsChanged = CASE
WHEN Col1 = PrevCol1
AND Col2 = PrevCol2
AND Col3 = PrevCol3
THEN 0 /*No change*/
ELSE 1 /*Iterate so new group created */
END
FROM cte_Prev
)
SELECT *,GroupID = SUM(IsChanged) OVER (PARTITION BY TestName ORDER BY ID)
INTO #Grouping
FROM cte_Compare
/*Raw unformatted data so you can see how it works*/
SELECT *
FROM #Grouping
/*Aggregated results*/
SELECT GroupID,TestName,Col1,Col2,Col3
,FromDate = MIN(FromDate)
,ToDate = MAX(ToDate)
,NumberOfRowsCollapsedIntoOneRow = COUNT(*)
FROM #Grouping
GROUP BY GroupID,TestName,Col1,Col2,Col3

Conditionally move values between columns

I have the following record set output:
ID Name Pay_Type Paid_Amnt Interest_Amnt
1 John Smith Benefit 1075 0
1 John Smith Interest 1.23 0
2 Tom Ryder Benefit 1123 0
3 Mark Thompson Benefit 1211 0
3 Mark Thompson Interest 1.34 0
What I'd like is for values with the Pay_Type = Interest to be placed in the Interest column.
Desired output:
ID Name Pay_Type Pay_Type 2 Paid_Amnt Interest_Amnt
1 John Smith Benefit Interest 1075 1.23
2 Tom Ryder Benefit NULL 1123 0
3 Mark Thompson Benefit Interest 1211 1.34
I tried something like the following:
Select row_number()over(partition by id, case when pay_type = 'Interest' then interest_amnt = paid_amnt
when pay_type = 'Interest' then paid_amnt = 0 end) as new_interest
Does anyone know how to get the desired results?
Thank you
declare #t table(id int, pay_type varchar(25), name varchar(100), paid_amnt float, interest_amnt float)
insert into #t values(1, 'Benefit', 'John Smith', 1075, 0),
(1, 'Interest', 'John Smith',1.23, 0),
(2, 'Benefit', 'Tom Ryder', 1123, 0),
(3, 'Benefit', 'Mark Thompson', 1211, 0),
(4, 'Interest', 'Mark Thompson', 1.34, 0)
select * from #t
Just in case you can have more than 2 records per person, I believe this will give you what you want, it utilizes a couple of subqueries and group by,
subquery x groups your records so you get the interest sums and benefits sums in a row per user,
subquery y uses CASE expressions to place the summed amounts into their proper columns or zero in case of it being Benefit/Interest and adds the pay type columns of pay_type1 and pay_type2 with values of Benefit and Interest respectively,
outer query groups everything together into 1 row per user, and sums their interest and benefit columns respectively:
SELECT y.[id] AS [ID], y.[name] AS [Name],
y.[pay_type1] AS [Pay_Type], y.[Pay_Type2], SUM(y.[Paid_Amnt]) AS [Paid_Amnt],
SUM(y.[Interest_Amnt]) AS [Interest_Amnt]
FROM
(
SELECT id, name, 'Benefit' AS [pay_type1], 'Interest' AS [pay_type2],
CASE WHEN pay_type = 'Benefit' THEN x.Amount ELSE 0 END AS [Paid_Amnt],
CASE WHEN pay_type = 'Interest' THEN x.Amount ELSE 0 END AS [Interest_Amnt]
FROM
(
SELECT id, pay_type, name, SUM(paid_amnt) AS [Amount]
FROM table as t
GROUP BY id, pay_type, name
) AS x
) AS y
GROUP BY y.[id], y.[name], y.[pay_type1], y.[pay_type2]

Select rowset with null value in first row of group by result set

I am stuck with a problem.
I have some data likes these :
Id Creation date Creation date hour range Id vehicule Id variable Value
1 2017-03-01 9:10 2017-03-01 9:00 1 6 0.18
2 2017-03-01 9:50 2017-03-01 9:00 1 3 0.50
3 2017-03-01 9:27 2017-03-01 9:00 1 3 null
4 2017-03-01 10:05 2017-03-01 10:00 1 3 0.35
5 2017-03-01 10:17 2017-03-01 10:00 1 3 0.12
6 2017-03-01 9:05 2017-03-01 9:00 1 5 0.04
7 2017-03-01 9:57 2017-03-01 9:00 1 5 null
I need to select rowset group by Id vehicule, Id variable, Creation date hour range and order by group by Id vehicule, Id variable, Creation date where the first Value is null but second value, third value, ... is not null. So, in the sample above, the following rowset :
Id Creation date Creation date hour range Id vehicule Id variable Value
3 2017-03-01 9:27 2017-03-01 9:00 1 3 null
2 2017-03-01 9:50 2017-03-01 9:00 1 3 0.50
Could you help me please ?
Thank you
You will have no luck with a group by in this case. I would give 2 "if exists" into the where clause to filter all IDs that fit your criteria:
(for example/not tested/probably takes forever)
select *
from yourTable y1
where id in
--the id must be in all IDs, where the first value of the set is null
--same ID instead of group by
(select 1 from yourTable y2 where y1.IDs = y2.IDs and
--the first in the set
y2.createdate = (select min(createdate) from yourtable y3 with sameid) and
y2.value is null)
AND
--the id must also be in the IDs, where there are values besides the first that are not null
id in (same select but with "not min" and "not null" obviously
hope that helped :)
Include the Value field in the ORDER BY clause and it will be sorted to the top because NULL has a lower practical value than a non-NULL value.
Assuming (because your middle paragraph is hard to understand) you want all the fields output but you want the 4th and 5th columns to produce some grouping of the output, with Value = NULL at the top of each group:
SELECT Id, CreatedDate, CreatedDateHourRange, IdVehicule, IdVariable, Value
ORDER BY IdVehicule, IdVariable, Value
I don't see any need for an actual GROUP BY clause.
I think it is unclear as to whether you want to limit the NULL Value rows in each block to just one row of NULL, but if you do you would need to state the order for which the datetime columns are sorted.
indeed group by was no use here. Also I wasn't sure where your 10:00 records were going to. Does this help?
;WITH CTE_ADD_SOME_LOGIC
AS
(
SELECT Id, CreationDate ,CreationDateHourRange ,IdVehicle ,IdVariable ,Value
, CASE WHEN Value IS NULL THEN 1 ELSE 0 END AS VALUE_IS_NULL FROM tbl
),
CTE_MORE_LOGIC
AS
(
SELECT Id, CreationDate ,CreationDateHourRange ,IdVehicle ,IdVariable ,Value,VALUE_IS_NULL
, RANK() OVER (ORDER BY CreationDateHourRange,VALUE_IS_NULL) AS RN FROM CTE_ADD_SOME_LOGIC),
CTE_ORDER
AS
(
SELECT Id, CreationDate ,CreationDateHourRange ,IdVehicle ,IdVariable ,Value,VALUE_IS_NULL, RN
, ROW_NUMBER() OVER(PARTITION BY RN ORDER BY RN,IdVehicle,IdVariable,CreationDate, VALUE_IS_NULL DESC) AS HIERARCHY FROM CTE_MORE_LOGIC
)
SELECT Id, CreationDate ,CreationDateHourRange ,IdVehicle ,IdVariable ,Value FROM CTE_ORDER WHERE HIERARCHY = 1
ORDER BY Id
Try this Query
DECLARE #Nulloccurrence INT=1 -- Give like 1,2,3 value to get first null occurrence 2 for 2nd null occurrence
SELECT TOP 2 *
FROM cte
WHERE Id <= (
SELECT ID FROM
(
SELECT Id, ROW_NUMBER()OVER( Order by id) AS Seq
FROM cte
WHERE (
CASE
WHEN CAST(variableValue AS VARCHAR) IS NULL
THEN 'P'
ELSE CAST(variableValue AS VARCHAR)
END
) = 'P'
)Dt
WHERE Dt.Seq=#Nulloccurrence
)
ORDER BY 1 DESC
Expected Result
Id Creationdate Creationdatehourrange Ids vehicleId variableValue
------------------------------------------------------------------------
3 2017-03-01 9:27 2017-03-01 9:00 1 3 NULL
2 2017-03-01 9:50 2017-03-01 9:00 1 3 0.50
For 'where the first Value is null but second value, third value, ... is not null' i suppose you want to filter cases where there is a null and a not null value at [Value] within the set you group by, to decide to filter or not that grouped row. This cannot be filtered on standard WHERE clause because at WHERE clause each row is filtered with conditions relevant to that row scope only. Simply put, each row filtered cannot 'see' other rows unless you use sub-query. You need to use HAVING clause (the comment out is for 2+ null records)
This will work:
> DECLARE #mytbl TABLE(Id INT, [Creation date] DATETIME, [Creation date
> hour range] DATETIME, [Id veh] INT, [Id var] INT, Value INT )
>
> INSERT INTO #mytbl VALUES (1,'2017-03-01 9:10 ','2017-03-01 9:00 ',1,
> 6, 0.18) INSERT INTO #mytbl VALUES (2,'2017-03-01 9:50 ','2017-03-01
> 9:00 ',1, 3, 0.50) INSERT INTO #mytbl VALUES (3,'2017-03-01 9:27
> ','2017-03-01 9:00 ',1, 3, NULL) INSERT INTO #mytbl VALUES
> (4,'2017-03-01 10:05','2017-03-01 10:00',1, 3, 0.35) INSERT INTO
> #mytbl VALUES (5,'2017-03-01 10:17','2017-03-01 10:00',1, 3, 0.12)
> INSERT INTO #mytbl VALUES (6,'2017-03-01 9:05 ','2017-03-01 9:00 ',1,
> 5, 0.04) INSERT INTO #mytbl VALUES (7,'2017-03-01 9:57 ','2017-03-01
> 9:00 ',1, 5, NULL)
>
> SELECT [Id veh], [Id var],[Creation date hour range] FROM #mytbl GROUP
> BY [Id veh], [Id var],[Creation date hour range] HAVING COUNT([Id
> veh]) - COUNT(Value) = 1
> --HAVING COUNT([Id veh]) - COUNT(Value) >= 1 ORDER BY [Id veh], [Id var],[Creation date hour range]

TSQL get COUNT of rows that are missing from right table

There was one other SIMILAR answer but it is 2 pages long and my requirement doesn't need that. I have 2 tables, tableA and a tableB, and I need to find the COUNTS of rows that are present in tableA but are not present in tableB OR if update_on in tableB is not today's date.
My tables:
tableA:
release_id book_name release_begin_date
----------------------------------------------------
1122 midsummer 2016-01-01
1123 fool's errand 2016-06-01
1124 midsummer 2016-04-01
1125 fool's errand 2016-08-01
tableB:
release_id book_name updated_on
-----------------------------------------
1122 midsummer 2016-08-17
1123 fool's errand 2016-08-16**
Expected result: Since each book is missing one release id, 1 is count. But in addition fool's errand's existing row in tableB has updated_on date of yesterday and not today, it needs to be counted in count_of_not_updated.
book_name count_of_missing count_of_not_updated
-------------------------------------------------------
midsummer 1 0
fool's errand 1 1
Note: Even though fool's errand is present in tableB, I need to show it in count_of_missing because it's updated_on date is yesterday and not today. I know it has to be a combination of a left join and something else, but the kicker here is not only getting the missing rows from left table but at the same time checking if the updated_on table was today's date and if not, count that row in count_of_not_updated.
select sum(case when b.release_id is null then 1 else 0 end) as noReleaseID
, sum(case when datediff(d, b.release_date, getdate()) > 0 then 1 else 0 end) as releaseDateNotToday
, a.release_id
from tableA a
left outer join tableB b on a.release_id = b.release_id
Group by a.release_id
This example uses a sum function on a case statement to add up the instances where the case statement returns true. Note that the current code assumes, as in your example, that you are looking to count all old release dates from table b - more steps would be required if each book has multiple old release dates in table b, and you only want to compare to the most recent release date.
Try this
DECLARE #tableA TABLE (release_id INT, book_name NVARCHAR(50), release_begin_date DATETIME)
DECLARE #tableB TABLE (release_id INT, book_name NVARCHAR(50), updated_on DATETIME)
INSERT INTO #tableA
VALUES
(1122, 'midsummer', '2016-01-01'),
(1123, 'fool''s errand', '2016-06-01'),
(1124, 'midsummer', '2016-04-01'),
(1125, 'fool''s errand', '2016-08-01')
INSERT INTO #tableB
VALUES
(1122, 'midsummer', '2016-08-17'),
(1123, 'fool''s errand', '2016-08-16')
;WITH TmpTableA
AS
(
SELECT
book_name,
COUNT(1) CountOfTableA
FROM
#tableA
GROUP BY
book_name
), TmpTableB
AS
(
SELECT
book_name,
COUNT(1) CountOfTableB,
SUM(CASE WHEN CONVERT(VARCHAR(11), updated_on, 112) = CONVERT(VARCHAR(11), GETDATE(), 112) THEN 0 ELSE 1 END) count_of_not_updated
FROM
#tableB
GROUP BY
book_name
)
SELECT
A.book_name ,
A.CountOfTableA - ISNULL(B.CountOfTableB, 0) AS count_of_missing,
ISNULL(B.count_of_not_updated, 0) AS count_of_not_updated
FROM
TmpTableA A LEFT JOIN
TmpTableB B ON A.book_name = B.book_name
Result:
book_name count_of_missing count_of_not_updated
-------------------- ---------------- --------------------
fool's errand 1 1
midsummer 1 1

SQL server select one record per day based on value in field

I have a followup question to this question.
SQL Server Get values of top three records and display in one row per person
ID Name Date1 Value2 Date2 Value2 Date3 Value3 Date4 Value4 Date5 Value5 Date6 Value6 Date7 Value7
12 John Smith 2011-06-27 14:06:10.517 None 2011-06-27 00:17:53.987 None 2011-06-26 21:56:07.577 Medium 2011-06-26 13:32:31.190 None 2011-06-26 02:47:54.357 None 2011-06-25 19:32:00.000 Medium 2011-06-25 13:43:22.000 Medium
12 Jack Smith 2011-06-27 05:54:59.320 None 2011-06-26 06:28:55.033 None 2011-06-25 16:25:00.000 Medium 2011-06-25 14:27:11.017 Large 2011-06-25 06:11:45.793 Large 2011-06-24 19:33:24.520 Medium 2011-06-24 06:17:35.887 None
I need to get one value per day. If there is a value that is not equal to 'None', I need that record for the given date.
Here is what the outcome should look like:
ID Name Date1 Value2 Date2 Value2 Date3 Value3 Date4 Value4 Date5 Value5 Date6 Value6 Date7 Value7
12 John Smith 2011-06-27 00:17:53.987 None 2011-06-26 21:56:07.577 Medium 2011-06-25 13:43:22.000 Medium
12 Jack Smith 2011-06-27 05:54:59.320 None 2011-06-26 06:28:55.033 None 2011-06-25 06:11:45.793 Large 2011-06-24 19:33:24.520 Medium
My raw data is in this format:
(Records I need are marked with *)
ID Name Date Value
12 JACK Smith 2011-06-27 05:54:59.320 None *
12 JACK Smith 2011-06-26 06:28:55.033 None *
12 JACK Smith 2011-06-25 16:25:00.000 Medium
12 JACK Smith 2011-06-25 14:27:11.017 Large
12 JACK Smith 2011-06-25 06:11:45.793 Large *
12 JACK Smith 2011-06-24 19:33:24.520 Medium *
12 JACK Smith 2011-06-24 06:17:35.887 None
12 JACK Smith 2011-06-23 00:30:28.363 None *
12 JACK Smith 2011-06-22 00:47:41.800 None *
12 JACK Smith 2011-06-21 06:03:55.000 None *
Any help is greatly appreciated.
Not clear what you're asking...
You can restrict your recordset with a WHERE clause (this will remove the record entirely)...probably easier to do this on your original recordset (at the link you posted) than on this revised recordset above...
WHERE value <> 'None'
Or you can keep the record, and just restrict the display with a function (many options -- here's one:)
Replace('None','')
...here's another one:
CASE value WHEN 'None' THEN '' ELSE value END
Something like this then... It will work, but it might have a typo, as I'm just typing it out without testing.
SELECT
ID,
Name,
Right(
-- The Right() function will strip-off the leading integer that you need to first add to the date so
-- you can get the record you want.
Min(
-- The Min() function will get a single record for you
-- the functions below will manipulate the date so that records with a non-'None' value are
-- guaranteed to have a larger date then records with a 'None' value. This is done by adding
-- an integer to the front of the date -- '0' for non-'None' values, and '1' for 'None' values.
Cast(CASE value WHEN 'None' THEN 1 ELSE 0 END as varchar(1))
-- The CASE statement outputs a 0 or 1
-- The Cast() function changes the output to text instead of a number, so you can use the
-- string concat (+) later.
+
-- string concatenation, which only works on text, not numbers
Cast(Date as varchar(25))
-- The Cast() function changes the date to text, so you can use it with the string concat above
)
, 23
-- 23 should be the number of characters in the date itself
-- adjust the number up or down as necessary.
) as myDate,
Value
FROM
Table
GROUP BY
ID,
Name,
Value
This should reduce your original recordset so that it only contains the records you want. Afterward, you can apply the horizontal solution that the #Manfred Sorg came-up with for your first question.
you want do transposition, i guess.
you should use pivot table some how that
table: pivot
values: 0, 1, 2, ...
the idea be able to position each value the each day in correct column and after group for get one single row
after you need do query
select
resultset.id, resultset.Name,
case when not max(date1) is null then max(date1)
else null end as date1,
case when not max(value1) is null then max(value1)
else '' end as value1,
...
...
...
from (
select mltwngd.id, mltwngd.Name,
//sorry that part is ugly, ugly,
case when i=0 then datedd(day, mltwngdg.periodstart, auxtable.i)
else '' end as date1,
case when i=0 then datedd(day, mltwngdg.periodstart, auxtable.i)
else '' end as value1,
...
...
...
from mylinealtable_with_nogooddesing mltwngd
inner join
(
select id, min(date) periodstart,
max(date) as periodend,
datediff("dd", max(date), min(date)) as days
from mylinealtable_with_nogooddesing
where ...
group by id
) as mltwngdg
on mltwngdg.id = mltwngd.id
inner join
(
select *
from pivot
where i >= 0 and i < #period_max_days
)auxtable
on auxtable.i >0 and auxtable.i < days
)resultset
group by resultset.id, resultset.Name
the idea simplified is
declare #aux table (id int, [name] varchar(20),
date1 datetime,
valor1 varchar(10),
date2 datetime,
valor2 varchar(10)
)
insert into #aux(id, [name], date1, valor1, date2, valor2)
values(1,'CARLOS','20110201','XP',NULL, '')
insert into #aux(id, [name], date1, valor1, date2, valor2)
values(1,'CARLOS',NULL, '','20110201','WIN7')
select * from #aux
select
x.id, x.name,
case when not max(date1) is null then max(date1)
else null end as date1,
case when not max(valor1) is null then max(valor1)
else null end as valor1,
case when not max(date2) is null then max(date2)
else null end as date2,
case when not max(valor1) is null then max(valor2)
else null end as valor2
from #aux x
group by x.id, x.name

Resources