I'm trying to fill 'Col4' null values with the values above using 'Col1' and 'Col3'. Here is a brief explanation of the columns:
Col1 - User Entry date
Col2 - Calendar date
Col3 - Difference between the dates in Col1
Col4 - Entry amount
What the data currently looks like:
| Col1 | Col2 | Col3 | Col4
| 2016-01-01 | 2016-01-01 | 3 | $10
| null | 2016-01-02 | null | null
| null | 2016-01-03 | null | null
| 2016-01-04 | 2016-01-04 | 1 | $2
| 2016-01-05 | 2016-01-05 | 2 | $7
| null | 2016-01-06 | null | null
| 2016-01-07 | 2016-01-07 | 3 | $5
| null | 2016-01-08 | null | null
| null | 2016-01-09 | null | null
Expected Results:
| Col1 | Col2 | Col3 | Col4
| 2016-01-01 | 2016-01-01 | 3 | $10
| null | 2016-01-02 | null | $10
| null | 2016-01-03 | null | $10
| 2016-01-04 | 2016-01-04 | 1 | $2
| 2016-01-05 | 2016-01-05 | 2 | $7
| null | 2016-01-06 | null | $7
| 2016-01-07 | 2016-01-07 | 3 | $5
| null | 2016-01-08 | null | $5
| null | 2016-01-09 | null | $5
The formula works by counting the number in Col3 and then copying the corresponding amount in Col4 to the rows below. Col3 defines how many rows below (including its own row).
I'm currently using Sybase. I don't have any ideas on how I can do this. Any help would be appreciated thanks.
Note: this is a sample of data and the dates go from 2000 - 2016
In SQL Server By given sample data we can achieve the above result Set by using CTE
Sample Data :
declarE #Table1 TABLE
(Col1 varchar(10), Col2 varchar(10), Col3 varchar(4), Col4 varchar(4))
;
INSERT INTO #Table1
(Col1, Col2, Col3, Col4)
VALUES
('2016-01-01', '2016-01-01', '3', '$10'),
(NULL, '2016-01-02', NULL, NULL),
(NULL, '2016-01-03', NULL, NULL),
('2016-01-04', '2016-01-04', '1', '$2'),
('2016-01-05', '2016-01-05', '2', '$7'),
(NULL, '2016-01-06', NULL, NULL),
('2016-01-07', '2016-01-07', '3', '$5'),
(NULL, '2016-01-08', NULL, NULL),
(NULL, '2016-01-09', NULL, NULL)
;
Script :
WITH cte
AS (SELECT T1.Col1,
T1.Col2,
T1.Col3,
Col4 = COALESCE(T1.Col4, (SELECT TOP 1 Col4
FROM #Table1 T2
WHERE T2.Col2 < T1.Col2
AND Col4 IS NOT NULL
ORDER BY Col2 DESC))
FROM #Table1 T1)
UPDATE T
SET
T.Col4 = C.Col4
FROM #Table1 T
INNER JOIN cte C
ON T.col2 = C.col2
WHERE T.col1 IS NULL
OR T.col2 IS NULL
OR T.col3 IS NULL
Select * from #Table1
Related
I would like to select records where values across 5 columns, if not null, are unequal. Any number of columns can be non null.
schema:
given table
**Schema (SQLite v3.30)**
CREATE TABLE test (
id INT,
col1 text,
col2 text,
col3 text,
col4 text,
col5 text
);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (1, 'EA', 'EA', null, null, null);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (2, 'EA', 'MT', null, null, null);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (3, null, 'EA', null, 'KG', null);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (4, null, null, 'KG', 'MT', 'AB');
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (5, null, null, 'EA', 'MT', 'EA');
---
**Query #1**
SELECT * FROM test;
| id | col1 | col2 | col3 | col4 | col5 |
| --- | ---- | ---- | ---- | ---- | ---- |
| 1 | EA | EA | | | |
| 2 | EA | MT | | | |
| 3 | | EA | | KG | |
| 4 | | | KG | MT | AB |
| 5 | | | EA | MT | EA |
---
Desired output
| id | col1 | col2 | col3 | col4 | col5 |
| --- | ---- | ---- | ---- | ---- | ---- |
| 2 | EA | MT | | | |
| 3 | | EA | | KG | |
| 4 | | | KG | MT | AB |
| 5 | | | EA | MT | EA |
EDIT: To clarify, id=5 is included in the output since not all values are the same. When I stated values across all columns are unequal, I meant if if any value is distinct from the rest of the non null values. To state it differently, I require records which have at least 1 non null value different from the other non null value.
Hmmm . . . this is tricky. Assuming that the empty values are NULL and no values are blank and you want all distinct values, you can do:
select t.*
from test t
where (col1 is null or col1 not in (coalesce(col2, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, ''))) and
(col2 is null or col2 not in (coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, ''))) and
(col3 is null or col3 not in (coalesce(col4, ''), coalesce(col5, ''))) and
(col4 is null or col4 not in (coalesce(col5, '')))
EDIT:
If you just want more than one distinct value, then:
select t.*
from test t
where col1 not in (coalesce(col2, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, '')) or
col2 not in (coalesce(col1, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, '')) or
col3 not in (coalesce(col1, ''), coalesce(col2, ''), coalesce(col4, ''), coalesce(col5, '')) or
col4 not in (coalesce(col1, ''), coalesce(col2, ''), coalesce(col3, ''), coalesce(col5, ''))
Here is a db<>fiddle.
Note: This does not return rows with only one value which technically do not meet your specifications.
You can aggregate on the union of each id with 1 of the columns and set the condition in the having clause:
with cte as (
select id from (
select id, col1 col from test union all
select id, col2 from test union all
select id, col3 from test union all
select id, col4 from test union all
select id, col5 from test
)
where col is not null
group by id
having count(distinct col) > 1
)
select * from test where id in cte
See the demo.
Results:
> id | col1 | col2 | col3 | col4 | col5
> -: | :--- | :--- | :--- | :--- | :---
> 2 | EA | MT | null | null | null
> 3 | null | EA | null | KG | null
> 4 | null | null | KG | MT | AB
> 5 | null | null | EA | MT | EA
I have two datasets like below:
1:
+---------------------------+
| Id | Col1 | Col2 | Col3 |
+---------------------------+
| 1 | abc | 0 | 01/01/2010 |
| 2 | def | 10 | 10/10/2011 |
+---------------------------+
2:
+-------------------------------------------+
| Id | Col4 | Col5 | Col6 |
+-------------------------------------------+
| 1 | abc | 0 | 01/01/2010 |
| 5 | xyz | 12 | 5/6/2013 |
+-------------------------------------------+
Now I want to combine both these into a single dataset which shows something like this:
+----------------------------------------------------------------------+
| ID | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+----------------------------------------------------------------------+
| 1 | abc | 0 | 01/01/2010 | abc | 0 | 01/01/2010 |
| 2 | def | 10 | 10/10/2011 | null | null | null |
| 5 | null | null | null | xyz | 12 | 5/6/2013 |
+----------------------------------------------------------------------+
The issue is not all ids in dataset 1 are in dataset 2 and vice versa. What i need as all data from datasets1 and 2 and only the common from 1 and 2 with 2 transposed with 1 as shown above. I have used pipe as a separator.
An inputs are highly appreciated. i tried everything like full outer join, inner join , CTE etc - nothing is working.
CREATE TABLE #TEMP1 (ID INT, Col1 VARCHAR(100), Col2 INT, Col3 DATETIME)
CREATE TABLE #TEMP2 (ID INT, Col4 VARCHAR(100), Col5 INT, Col6 DATETIME)
INSERT INTO #TEMP1 VALUES (1,'abc',0,'1/1/2010')
INSERT INTO #TEMP1 VALUES (1,'def',0,'1/1/2010')
INSERT INTO #TEMP2 VALUES (1,'abc',0,'1/1/2010')
INSERT INTO #TEMP2 VALUES (1,'def',0,'1/1/2010')
SELECT DISTINCT A.ID,A.Col1,A.Col2,A.Col3,B.Col4,B.Col5,B.Col6
FROM #TEMP1 A
FULL OUTER JOIN #TEMP2 B ON A.ID = B.ID
Thanks.
Try using below SQL :
select t1.Id , Col1 , Col2 , Col3 , Col4 , Col5 , Col6
from temp1 t1 left join temp2 t2
on t1.Id=t2.Id
union
select t2.Id , Col1 , Col2 , Col3 , Col4 , Col5 , Col6
from temp1 t1 right join temp2 t2
on t1.Id=t2.Id
Also, i tried on fiddle for you :
http://sqlfiddle.com/#!2/d60a1e/5
I have a table (TestTable) as follows
PK | COL1 | COL2 | COL3 | COL4 | COL5
1 | 1 | NULL | NULL | NULL | NULL
2 | NULL | 43 | 1.5 | 7.8 | NULL
3 | NULL | NULL | NULL | NULL | 1
4 | 1 | NULL | NULL | NULL | NULL
5 | NULL | 48 | 10.5 | 17.8 | NULL
6 | NULL | NULL | NULL | NULL | 1
I would like a result as follows
PK | COL1 | COL2 | COL3 | COL4 | COL5
1 | 1 | 43 | 1.5 | 7.8 | 1
2 | 1 | 48 | 10.5 | 17.8 | 1
I have tried the following
Select
[COL1],
[COL2],
[COL3],
[COL4],
(select top 1
[COL5] from TestTable
where [COL5] is not null and PK <= t1.pk
order by PK DESC) as [COL5]
FROM TestTable as t1
Where
[COL1] IS NOT NULL AND
[COL2] IS NOT NULL AND
[COL3] IS NOT NULL AND
[COL4] IS NOT NULL
The script works however I get empty result set. Any thoughts?
It looks like you have a value in col1 followed by a set of rows that should be combined into one row until the next value in col1.
If so, you can do this by assigning to each row a count -- the number of non-null values in col1 on or before the row. This can then be used for aggregation.
You don't mention the database, so I'll do this using a correlated subquery:
select row_number() over (order by max(pk)) as pk,
max(col1) as col1,
max(col2) as col2,
max(col3) as col3,
max(col4) as col4,
max(col5) as col5
from (select t.*,
(select count(t2.col1)
from testtable t2
where t2.pk <= t.pk
) as grpid
from testtable t
) t
group by grpid;
You don't have any rows in TestTable where
[COL1] IS NOT NULL AND
[COL2] IS NOT NULL AND
[COL3] IS NOT NULL AND
[COL4] IS NOT NULL
Sorry If this is duplicate...
I have this table (Id,Col1,Col2,..,Col3) but I want to have results grouped like this
ID1value group,
Col1Value,
Col2Value,
Col3Value
ID2value group,
ID2Col1Value,
ID2Col2Value,
ID2Col3Value
ID3value group,
ID3Col1Value,
ID3Col2Value,
ID3Col3Value
How to do it?
I have tried PIVOT but I think this does not return good result
It sounds like you want UNPIVOT as opposed to PIVOT:
DECLARE #T TABLE (ID INT, Col1 VARCHAR(15), Col2 VARCHAR(15), Col3 VARCHAR(15))
INSERT #T (ID, Col1, Col2, Col3)
VALUES
(1, 'ID1Col1Value', 'ID1Col2Value', 'ID1Col3Value'),
(2, 'ID2Col1Value', 'ID2Col2Value', 'ID2Col3Value'),
(3, 'ID3Col1Value', 'ID3Col2Value', 'ID3Col3Value');
SELECT upvt.ID,
upvt.Value
FROM #T
UNPIVOT
( Value
FOR [Group] IN ([Col1], [Col2], [Col3])
) AS upvt;
Giving:
+----+--------------+
| ID | Value |
+----+--------------+
| 1 | ID1Col1Value |
| 1 | ID1Col2Value |
| 1 | ID1Col3Value |
| 2 | ID2Col1Value |
| 2 | ID2Col2Value |
| 2 | ID2Col3Value |
| 3 | ID3Col1Value |
| 3 | ID3Col2Value |
| 3 | ID3Col3Value |
+----+--------------+
I try to consolidate two rows of the same table whereas each row has a priority.
The value of interest is the value having priority 1 if it is not NULL; otherwise the value with priority 0.
An example data source could be:
| Id | GroupId | Priority | Col1 | Col2 | Col3 | ... | Coln |
-----------------------------------------------------------------
| 1 | 1 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 2 | 1 | 1 | NULL | NULL | 2.83 | ... | bar |
| 3 | 2 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 4 | 2 | 1 | 23 | NULL | 2.83 | ... | NULL |
and I want to have:
| GroupId | Col1 | Col2 | Col3 | ... | Coln |
-------------------------------------------------
| 1 | NULL | 4711 | 2.83 | ... | bar |
| 2 | 23 | 4711 | 2.83 | ... | f00 |
Is there a generic way in TSQL without the need to check each column explicitly?
SELECT
t1.GroupId,
ISNULL(t2.Col1, t1.Col1) as Col1,
ISNULL(t2.Col2, t1.Col2) as Col2,
ISNULL(t2.Col3, t1.Col3) as Col3,
...
ISNULL(t2.Coln, t1.Coln) as Coln
FROM mytable t1
JOIN mytable t2 ON t1.GroupId = t2.GroupId
WHERE
t1.Priority = 0 AND
t2.Priority = 1
Regards
I'll elaborate the ROW_NUMBER() solution that #KM suggested since IMO it's the best solution for this. (In CTE form for easier readability)
WITH cte AS (
SELECT
t1.GroupId,
t1.Col1,
t1.Col2,
ROW_NUMBER() OVER(PARTITION BY t1.GroupId ORDER BY ISNULL(GroupId ,-1) ) AS [row_id]
FROM
mytable t1
)
SELECT
*
FROM
cte
WHERE
row_id = 1
That will give you the row with the highest priority (according to your rules) for each GroupId in mytable.
ROW_NUMBER and RANK are two of my favorite TSQL tricks. http://msdn.microsoft.com/en-us/library/ms186734.aspx
edit: Another favorite of mine is PIVOT/UNPIVOT which you can use to transpose rows/columns which is another way of going about this type of problem. http://msdn.microsoft.com/en-us/library/ms177410.aspx
I think this would do what you are asking for without using isnull for every column
select
*
from
mytable t1
where
priority=(select max(priority) from mytable where groupid=t1.groupid group by groupid)