my current tabular output is
---------------------------------------------------
| id col1 col2 |
---------------------------------------------------
| 1 | test1 | 1 |
| 2 | test11 | 0 |
| 3 | test12 | 0 |
| 4 | test13 | 0 |
| 5 | test14 | 0 |
| 6 | test2 | 2 |
| 7 | test21 | 0 |
| 8 | test22 | 0 |
| 9 | test23 | 0 |
| 10 | test24 | 0 |
---------------------------------------------------
Expected output is
---------------------------------------------------
| id col1 col2 |
---------------------------------------------------
| 1 | test1 | 1 |
| 2 | test11 | 1 |
| 3 | test12 | 1 |
| 4 | test13 | 1 |
| 5 | test14 | 1 |
| 6 | test2 | 2 |
| 7 | test21 | 2 |
| 8 | test22 | 2 |
| 9 | test23 | 2 |
| 10 | test24 | 2 |
---------------------------------------------------
Is this possible without cursor? Is there a way that I can add top row value to current row value on a condition when current row value is 0?
You could find the last non-zero value of col2 like:
select id
, col1
, (
select top 1 col2
from YourTable yt2
where yt2.id <= yt1.id
and yt2.col2 <> 0
order by
yt2.id desc
)
from YourTable yt1
Example at SQL Fiddle.
It doesn't look like you're after a running sum. This should work in 2005 or later:
DECLARE #tmp TABLE
(
id INT PRIMARY KEY
, col1 VARCHAR(20)
, col2 INT
);
INSERT #tmp
VALUES
(1, 'test1', 1)
, (2, 'test11', 0)
, (3, 'test12', 0)
, (4, 'test13', 0)
, (5, 'test14', 0)
, (6, 'test2', 2)
, (7, 'test21', 0)
, (8, 'test22', 0)
, (9, 'test23', 0)
, (10, 'test24', 0);
SELECT
t1.id
, t1.col1
, CASE t1.col2
WHEN 0
THEN t2.col2
ELSE
t1.col2
END col2
FROM
#tmp t1
OUTER APPLY
(
SELECT
TOP 1 col2
FROM
#tmp t3
WHERE
t3.id <= t1.id
AND
t3.col2 > 0
ORDER BY
t3.id DESC
) t2
Related
I have a table with this data:
ID | Data
----+-----
1 | ABC
2 | A
3 | A
4 | AC
5 | B
I would like to extract for each row each character and the ID from it come like this:
ID | Data_extract
----+-----------
1 | A
1 | B
1 | C
2 | A
3 | A
4 | A
4 | C
5 | B
I'm using Microsoft SQL Server
Thanks
You can use Common table expressions to achieve this.
DECLARE #t table(ID int, val VARCHAR(10))
INSERT INTO #t
VALUES
(1 ,'ABC')
,(2 ,'A')
,(3 ,'A')
,(4 ,'AC')
,(5 ,'B');
;WITH CTE_VAL AS
(
SELECT id,
cast((case when len(val) > 1 then left(val,1) else val end) as nvarchar(50)) as nval, 1 as lvl
from #t
UNION ALL
SELECT t.id,
cast(substring(val,lvl+1,1) as nvarchar(50)) as nval, lvl+1
FROM #t AS t INNER JOIN CTE_VAL AS c
ON t.ID = c.ID
WHERE len(val) > 1 and lvl < len(val)
)
SELECT id,nval FROM CTE_VAL
order by id
+----+------+
| id | nval |
+----+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | A |
| 3 | A |
| 4 | A |
| 4 | C |
| 5 | B |
+----+------+
In my query, I am doing multiple types of ranking and for one of ranking types, I want to rank the row only if certain column is not null. Else I don't want ranking to happen.
For example here's a sample table:
+------+------------+------------+--------+--------+
| col1 | col2 | col3 | rank 1 | rank 2 |
+------+------------+------------+--------+--------+
| a | 2018-01-20 | 2018-03-04 | 2 | 2 |
| a | 2018-01-24 | 2018-04-04 | 1 | 1 |
| b | 2018-01-02 | 2018-05-03 | 1 | 1 |
| c | 2017-01-02 | 2017-05-08 | 3 | 2 |
| d | 2016-05-24 | null | 1 | null |
| c | 2018-02-05 | 2018-05-03 | 2 | 1 |
| c | 2018-07-28 | null | 1 | null |
+------+------------+------------+--------+--------+
rank1 is calculated alright based on partition by col1 order by col2 desc
rank 2 should be calculated the same way, but only when when col3 is null, else it should be null.
How can I achieve both ranks in a single query? I tried to use case statement for rank2, but it skips the ranking when col3 is null,
If I understand corrcly, you can try to use CASE WHEN with sum window function
CASE WHEN check col3 isn't null do accumulate else display NULL
CREATE TABLE T(
col1 VARCHAR(5),
col2 DATE,
col3 DATE
);
INSERT INTO T VALUES ( 'a' , to_date('2018-01-20','YYYY-MM-DD') , to_date('2018-03-04','YYYY-MM-DD'));
INSERT INTO T VALUES ( 'a' , to_date('2018-01-24','YYYY-MM-DD') , to_date('2018-04-04','YYYY-MM-DD'));
INSERT INTO T VALUES ( 'b' , to_date('2018-01-02','YYYY-MM-DD') , to_date('2018-05-03','YYYY-MM-DD'));
INSERT INTO T VALUES ( 'c' , to_date('2017-01-02','YYYY-MM-DD') , to_date('2017-05-08','YYYY-MM-DD'));
INSERT INTO T VALUES ( 'd' , TO_DATE('2016-05-24','YYYY-MM-DD') , null);
INSERT INTO T VALUES ( 'c' , TO_DATE('2018-02-05','YYYY-MM-DD') , to_date('2018-05-03','YYYY-MM-DD'));
INSERT INTO T VALUES ( 'c' , TO_DATE('2018-07-28','YYYY-MM-DD') , null);
Query 1:
select t1.*,
rank() OVER(partition by col1 order by col2 desc) rank1,
(CASE WHEN COL3 IS NOT NULL THEN
SUM(CASE WHEN COL3 IS NOT NULL THEN 1 ELSE 0 END) OVER(partition by col1 order by col2 desc)
ELSE
NULL
END) rank2
FROM T t1
Results:
| COL1 | COL2 | COL3 | RANK1 | RANK2 |
|------|----------------------|----------------------|-------|--------|
| a | 2018-01-24T00:00:00Z | 2018-04-04T00:00:00Z | 1 | 1 |
| a | 2018-01-20T00:00:00Z | 2018-03-04T00:00:00Z | 2 | 2 |
| b | 2018-01-02T00:00:00Z | 2018-05-03T00:00:00Z | 1 | 1 |
| c | 2018-07-28T00:00:00Z | (null) | 1 | (null) |
| c | 2018-02-05T00:00:00Z | 2018-05-03T00:00:00Z | 2 | 1 |
| c | 2017-01-02T00:00:00Z | 2017-05-08T00:00:00Z | 3 | 2 |
| d | 2016-05-24T00:00:00Z | (null) | 1 | (null) |
I think you might want:
select count(col3) over (partition by col1 order by col2 desc)
Note that this is equivalent to row_number() rather than rank(). For your data these are equivalent.
I need help with ranking of rows in one table.
+-----+-------+-------------+------------+-------+------+
| ID | group | typeInGroup | rankOfType | score | Rank |
+-----+-------+-------------+------------+-------+------+
| 1 | a | type1 | 1 | 40 | |
| 2 | a | type2 | 2 | 55 | |
| 3 | a | type1 | 1 | 20 | |
| 4 | b | type3 | 3 | 80 | |
| 5 | b | type2 | 2 | 60 | |
| 6 | b | type1 | 1 | 70 | |
| 7 | b | type1 | 1 | 70 | |
+-----+-------+-------------+------------+-------+------+
I am basically looking for solution which would give me order for last column "Rank".
Each "group" has up to 9 "typeInGroup" which are ranked by 1-9 in column "rankOfTypes". Each "typeInGroup" has "score". When i am calculating last column "Rank" i look at the "score" and "rankOfType" column.
The row with the higgest score should be ranked first unless there is row with "rankOfType" column that has lower value and score that is <= 15 than the score we have been looking at. Order of rows with same "score" and "rankOfType" is not important.
I should do this check for every single row in group and in the end end with something like this:
+-----+-------+-------------+------------+-------+------+
| ID | group | typeInGroup | rankOfType | score | Rank |
+-----+-------+-------------+------------+-------+------+
| 1 | a | type1 | 1 | 40 | 1 |
| 2 | a | type2 | 2 | 55 | 2 |
| 3 | a | type1 | 1 | 20 | 3 |
| 4 | b | type3 | 3 | 80 | 3 |
| 5 | b | type2 | 2 | 60 | 4 |
| 6 | b | type1 | 1 | 70 | 1 |
| 7 | b | type1 | 1 | 70 | 2 |
+-----+-------+-------------+------------+-------+------+
Any idea how to do this?
the CROSS APPLY query, checks for any rows that meet your special requirement, if exists, than that row will have higher priority
try it out with larger data set and verify the result
declare #tbl table
(
ID int,
Grp char,
typeInGrp varchar(5),
rankOfType int,
score int
)
insert into #tbl select 1, 'a', 'type1', 1, 40
insert into #tbl select 2, 'a', 'type2', 2, 55
insert into #tbl select 3, 'a', 'type1', 1, 20
insert into #tbl select 4, 'b', 'type3', 3, 80
insert into #tbl select 5, 'b', 'type2', 2, 60
insert into #tbl select 6, 'b', 'type1', 1, 70
insert into #tbl select 7, 'b', 'type1', 1, 70
select *,
[rank] = row_number() over (partition by Grp
order by case when cnt > 0 then 1 else 2 end,
score desc)
from #tbl t
cross apply
(
select cnt = count(*)
from #tbl x
where x.Grp = t.Grp
and x.ID <> t.ID
and x.rankOfType > t.rankOfType
and x.score - t.score <= 15
) s
order by ID
+----+--------+-----------+
| ID | ID_DEP | OPERATION |
+----+--------+-----------+
| 1 | 2 | T1 |
| 2 | 2 | T1 |
| 3 | 2 | T4 |
| 4 | 1 | T1 |
| 5 | 1 | T1 |
| 6 | 1 | T4 |
| 7 | 4 | T6 |
| 8 | 3 | T1 |
| 9 | 3 | T1 |
| 10 | 5 | T9 |
+----+--------+-----------+
Hey guys, help me with that simple question.
How to select only these id's (ID_DEP) that have ONLY T1 from Operation column and not other value.
I'd use a WHERE NOT EXISTS
Test Data
IF OBJECT_ID('tempdb..#TestData') IS NOT NULL DROP TABLE #TestData
CREATE TABLE #TestData (ID int, ID_DEP int, OPERATION varchar(2))
INSERT INTO #TestData (ID, ID_DEP, OPERATION)
VALUES
(1,2,'T1')
,(2,2,'T1')
,(3,2,'T4')
,(4,1,'T1')
,(5,1,'T1')
,(6,1,'T4')
,(7,4,'T6')
,(8,3,'T1')
,(9,3,'T1')
,(10,5,'T9')
Query
SELECT
td.*
FROM #TestData td
WHERE NOT EXISTS (SELECT 1 FROM #TestData sub WHERE sub.OPERATION <> 'T1' AND td.ID_DEP = sub.ID_DEP)
Output
ID ID_DEP OPERATION
8 3 T1
9 3 T1
Basically, the NOT EXISTS returns any rows where the value IS NOT 'T1'. If an ID_DEP exists then we want to exclude this from the result set.
Please refer the below script
declare #table1 table
(
col1 int
)
declare #table2 table
(
col2 int
)
insert into #table1 values(1)
insert into #table1 values(2)
insert into #table1 values(3)
insert into #table1 values(5)
insert into #table1 values(7)
insert into #table2 values(1)
insert into #table2 values(3)
insert into #table2 values(3)
insert into #table2 values(6)
insert into #table2 values(4)
insert into #table2 values(7)
Case 1:
select * from #table1 a left outer join #table2 b on a.col1=b.col2
order by col1
Result 1:
col1 col2
----------- -----------
| 1 | 1 |
| 2 | NULL |
| 3 | 3 |
| 3 | 3 |
| 5 | NULL |
| 7 | 7 |
---------------------------
Case 2:
select * from #table1 a right outer join #table2 b on a.col1=b.col2
order by col2
Result 2:
col1 col2
----------- -----------
| 1 | 1 |
| 3 | 3 |
| 3 | 3 |
| NULL | 4 |
| NULL | 6 |
| 7 | 7 |
---------------------------
Actual Case:
select * from #table1 a full outer join #table2 b on a.col1=b.col2
Actual Result:
col1 col2
----------- -----------
| 1 | 1 |
| 2 | NULL |
| 3 | 3 |
| 3 | 3 |
| 5 | NULL |
| 7 | 7 |
| NULL | 6 |
| NULL | 4 |
---------------------------
Expected Result:
col1 col2
----------- -----------
| 1 | 1 |
| 2 | NULL |
| 3 | 3 |
| 3 | 3 |
| NULL | 4 |
| 5 | NULL |
| NULL | 6 |
| 7 | 7 |
---------------------------
I tried union all with left and right join query but it doubles the result set. Is there a way that I can get this expected output.
Thanks,
Esen.
You can use
SELECT *
FROM #table1 a
FULL OUTER JOIN #table2 b
ON a.col1 = b.col2
ORDER BY Isnull(col1, col2)
to get your desired order. Without an ORDER BY no ordering is guaranteed.