Below is my table structure.
declare #t1 table (id int identity,val int not null,datatype1 int null,datatype2 int null,datatype3 int null,datatype4 int null,type int)
declare #t2 table (id int identity,val int not null,datatype1 int null,datatype2 int null,datatype3 int null,datatype4 int null,type int)
insert into #t1 values (10,1,0,0,0,1),(31,1,0,0,0,1),(20,1,0,0,0,1),(30,1,0,0,0,1)
insert into #t2 values (31,0,1,0,0, 2),(4,0,0,1,0,3),(12,0,0,0,1,4),(31,0,0,0,1,4)
select * from #t1;
select * from #t2;
i am combining 2 table data with below query.
select val,max(datatype1) datatype1,max(datatype2)datatype2,max(datatype3)datatype3,max(datatype4)datatype4 from (
select * from #t1
union all
select * from #t2
) as data group by val
i need to change the logic if val is 31 and type=2 in #t2 ,
for these cases i need get 2 rows for val 31 and other cases only distinct values
Expected Result:
val datatype1 datatype2 datatype3 datatype4
4 0 0 1 0
10 1 0 0 0
12 0 0 0 1
20 1 0 0 0
30 1 0 0 0
31 1 0 0 1
31 0 1 0 0 --- only if in #t2 val =31 and type=2
pls let me knwwat need to be changed for only value 31 and type=2
Based on provided data looks like CASE expression is the way to go:
select val,
max(datatype1) datatype1,
max(datatype2) datatype2,
max(datatype3) datatype3,
max(datatype4) datatype4
from (
select 't1' AS tab_name, * from #t1
union all
select 't2' AS tab_name, * from #t2
) as data
group by val, CASE WHEN tab_name = 't2' and val=31 and type=2 THEN 1 END;
-- creating subgroup for this specific conditions
db<>fiddle demo
Related
I have create a table and inserted some records.
CREATE TABLE #t
(
ID INT IDENTITY(1,1) PRIMARY KEY,
val INT NULL
);
-- INSERT 10 values: 3 NULL, 7 integers
INSERT INTO #t SELECT NULL;
INSERT INTO #t SELECT NULL;
INSERT INTO #t SELECT NULL;
INSERT INTO #t SELECT 5;
INSERT INTO #t SELECT 7;
INSERT INTO #t SELECT 8;
INSERT INTO #t SELECT 9;
INSERT INTO #t SELECT 9;
INSERT INTO #t SELECT 11;
INSERT INTO #t SELECT 12;
Now when i am executing script to find quartile
SELECT *,
NTILE(4) OVER (ORDER BY val) As Q
FROM #t;
i am getting values as
ID val Q
---------
1 NULL 1
2 NULL 1
3 NULL 1
4 5 2
5 7 2
6 8 2
7 9 3
8 9 3
9 11 4
10 12 4
I don't want "Null" records and don't want to use "Where" clause.
I want result like this
ID val Q
---------
4 5 1
5 7 1
6 8 2
7 9 2
8 9 3
9 11 3
10 12 4
It strikes me that you might want NULL for the NTILE() value and to ignore the values for the calculation. You can get this by doing:
SELECT t.*,
(CASE WHEN val IS NOT NULL
THEN NTILE(4) OVER (PARTITION BY (CASE WHEN val IS NOT NULL THEN 'NOTNULL' ELSE 'NULL' END)
ORDER BY val
)
END) as Q
FROM #t t;
Or, perhaps more simply:
SELECT id, val, NTILE(4) OVER (ORDER BY val) As Q
FROM #t t
WHERE val IS NOT NULL
UNION ALL
SELECT id, val, NULL as q
FROM #t t
WHERE val IS NULL;
You could try this:
SELECT *,
CASE
WHEN val IS NULL THEN NULL
ELSE NTILE(4) OVER (
--Split NULL and NOT NULL into 2 different groups
PARTITION BY CASE WHEN val IS NULL THEN 0 ELSE 1 END
ORDER BY val)
END AS Q
FROM #t
You'll get:
ID val Q
1 NULL NULL
2 NULL NULL
3 NULL NULL
4 5 1
5 7 1
6 8 2
7 9 2
8 9 3
9 11 3
10 12 4
Having data like this:
id text bit date
1 row 1 2016-11-24
2 row 1 2016-11-25
3 row 0 2016-11-26
4 row 1 2016-11-27
I want to select the data based on where the text and bit columns are distinct, but based on some order, in this case the id, the data changes between two identical rows, it should duplicate this row on the selection.
So, if I use distinct on SQL, I would get rows 1 and 3, but I want to retreive rows 1, 3 and 4, because even 1 and 4 being identical, row 3 is between then when ordering by id.
With a larger dataset, like:
id text bit date
1 row 1 2016-11-24
2 row 1 2016-11-25
3 row 0 2016-11-26
4 row 1 2016-11-27
5 foo 1 2016-11-28
6 bar 1 2016-11-29
7 row 1 2016-11-30
8 row 0 2016-12-01
9 row 0 2016-12-02
10 row 1 2016-12-03
Again, selecting with distinct on text and bit columns, the query would retrieve rows 1,3,5 and 6, but actually I want rows 1,3,4,5,6,7,8 and 10.
;with tb(id,[text],[bit],[date]) AS (
SELECT 1,'row',1,'2016-11-24' union
SELECT 2,'row',1,'2016-11-25' union
SELECT 3,'row',0,'2016-11-26' union
SELECT 4,'row',1,'2016-11-27' union
SELECT 5,'foo',1,'2016-11-28' union
SELECT 6,'bar',1,'2016-11-29' union
SELECT 7,'row',1,'2016-11-30' union
SELECT 8,'row',0,'2016-12-01' union
SELECT 9,'row',0,'2016-12-02' union
SELECT 10,'row',1,'2016-12-03')
select t1.* from tb as t1
OUTER APPLY (select top 1 [text],[bit] from tb as tt where tt.id<t1.id order by id desc ) as t2
where t1.[text]!=isnull(t2.[text],'') or t1.[bit]!=isnull(t2.[bit],1-t1.[bit])
result set:
1 row 1 2016-11-24
3 row 0 2016-11-26
4 row 1 2016-11-27
5 foo 1 2016-11-28
6 bar 1 2016-11-29
7 row 1 2016-11-30
8 row 0 2016-12-01
10 row 1 2016-12-03
It seems that you need a row-by-row operator. You need to know if the new row is the same as the previous one or not. If it is, neglect it, if not, keep it. Here is my solution:
declare #text varchar(100)=(select [text] from Mytable where id = 1)
declare #bit bit = (select [bit] from Mytable where id = 1)
declare #Newtext varchar(100)
declare #Newbit bit
declare #Mytable table(id int, [text] varchar(100), [bit] bit)
Insert into #Mytable select id,text, bit from Mytable where id = 1
declare #counter int =2
while #counter<=(select COUNT(*) from MyTable)
Begin
select #Newtext=(select [text] from Mytable where id = #counter)
select #Newbit=(select [bit] from Mytable where id = #counter)
IF #Newtext!=#text or #Newbit!=#bit
Begin
Insert into #Mytable
select * from Mytable where id = #counter
End
set #text = #Newtext
set #bit = #Newbit;
set #counter = #counter+1
END
select * from #Mytable
I'm trying to write a incremental update statement using SQL Server 2012.
Current Data:
RecNo Budget_ID Item_Code Revision
---------------------------------------
1 16 xxx 2
2 16 xxx NULL
3 16 xxx NULL
12 19 yyy 3
13 19 yyy NULL
14 19 yyy NULL
15 19 yyy NULL
Expected result:
RecNo Budget_ID Item_Code Revision
---------------------------------------
1 16 xxx 2
2 16 xxx 1
3 16 xxx 0
12 19 yyy 3
13 19 yyy 2
14 19 yyy 1
15 19 yyy 0
However with following approach, I ended up with the result set as below.
UPDATE a
SET a.Revision = (SELECT MIN(b.Revision)
FROM [dbo].[foo] b
WHERE b.item_code = a.item_code
AND b.budget_id = a.budget_id
GROUP BY b.item_code ) -1
FROM [dbo].[foo] a
WHERE a.Revision is NULL
Result:
RecNo Budget_ID Item_Code Revision
---------------------------------------
1 16 xxx 2
2 16 xxx 1
3 16 xxx 1
12 19 yyy 3
13 19 yyy 2
14 19 yyy 2
15 19 yyy 2
Can anyone help me to get this right?
Thanks in advance!
Try this:
;with cte as
(select *, row_number() over (partition by budget_id order by rec_no desc) rn from dbo.foo)
update cte
set revision = rn - 1
Basically, since the revision value seems to be decreasing with increase in rec_no, we simply use the row_number() function to get row number of each record within the subset of all records with a particular budget_id, sorted in descending order of rec_no. Since the least possible value of row_number() will be 1, we subtract 1 so that the last record in the partition will have revision set to 0 instead 1.
You may test the code here
I found this example from this link https://stackoverflow.com/a/13629639/1692632
First you select MIN value to some variable and then you can update table by decreasing variable at same time.
DECLARE #table TABLE (ID INT, SomeData VARCHAR(10))
INSERT INTO #table (SomeData, ID) SELECT 'abc', 6 ;
INSERT INTO #table (SomeData) SELECT 'def' ;
INSERT INTO #table (SomeData) SELECT 'ghi' ;
INSERT INTO #table (SomeData) SELECT 'jkl' ;
INSERT INTO #table (SomeData) SELECT 'mno' ;
INSERT INTO #table (SomeData) SELECT 'prs' ;
DECLARE #i INT = (SELECT ISNULL(MIN(ID),0) FROM #table)
UPDATE #table
SET ID = #i, #i = #i - 1
WHERE ID IS NULL
SELECT *
FROM #table
I'm not sure if this will do the trick but you can try with
Update top(1) a
SET a.Revision = (Select MIN(b.Revision)
FROM [dbo].[foo] b where b.item_code = a.item_code and b.budget_id = a.budget_id
group by b.item_code ) -1
FROM [dbo].[foo] a
WHERE a.Revision is NULL
and repeat until there's no changes left
Update Data
set Revision = x.Revision
from
(select RecNo, Budget_ID, Item_Code, case when Revision is null then ROW_NUMBER() over(partition by Budget_ID order by RecNo desc) - 1 else Revision end Revision
from Data
) x
where x.RecNo = data.RecNo
You basically use ROW_NUMBER() to count backwards for each Budget_ID, and use that row number minus 1 where Revision is null. This is basically the same as Shree's answer, just without the CTE.
I have the below input table
Input
ID Row Data
1 1 a2b
1 2 p1d1
2 1 abcd
Expected Output
ID RowCol Chars
1 a1 a
1 b1 X
1 c1 X
1 d1 b
1 a2 p
1 b2 X
1 c2 d
1 d2 X
2 a1 a
2 b1 b
2 c1 c
2 d1 d
Each numbers in the data column will be treated as that many X's. So if the expand the first resord which is 'a2b'
it becomes aXXB. that is the length will be 4. Representing in columns it will be a, b ,c and d.
And since, it is in the first row, therefore, the output will be
ID RowCol Chars
1 a1 a
1 b1 X
1 c1 X
1 d1 b
The ddl is as under
Declare #t table(ID int , Row int, Data varchar(10))
Insert into #t
Select 1, 1,'a2b' Union All Select 1,2,'p1d1' Union All Select 2,1,'abcd'
Looking for a cte based solution.
Thanks in advance
As i promised i would make a better solution today. I know you will like and most likely use it.
DECLARE #t TABLE(ID INT , Row INT, Data VARCHAR(10))
Insert INTO #t
SELECT 1, 1,'a2b' UNION All SELECT 1,2,'p1d1' UNION All SELECT 2,1,'abcd'
;WITH cte(id, row, num, data)
AS (
SELECT id, row, 1 num,CAST(data as VARCHAR(10)) data
FROM #t
UNION ALL
SELECT ch.id, row, CH.num +1, CAST(REPLACE(ch.data, ch.num, REPLICATE('X', ch.num)) as VARCHAR(10))
FROM cte ch
WHERE ch.num < 9 )
, cte2(id, rowcol, row, num, data, chars, LEVEL) as
(SELECT id, CHAR(97) + CAST(row AS CHAR) rowcol, row, num, data, SUBSTRING(data, 1, 1), 1 LEVEL
FROM cte
where num = 9
UNION all
SELECT id, CHAR(97 + LEVEL) + CAST(row AS CHAR) rowcol, row, num, data, SUBSTRING(data, LEVEL + 1, 1), LEVEL + 1
FROM cte2 ch
where LEVEL < LEN(data)
)
SELECT ID, rowcol, chars
FROM CTE2
ORDER BY id, data, rowcol
I need to create a query that will sum the number of True(1) and False(0) into two separate columns from one bit field.
I'm joining 3 tables and need it to be something like:
Attribute | Class | Pass | Fail
I will be grouping on Attribute and Class.
Something like this:
SUM(CASE WHEN ColumnName = 1 THEN 1 ELSE 0 END) AS Pass,
SUM(CASE WHEN ColumnName = 0 THEN 1 ELSE 0 END) AS Fail
This works (at least in SQL 2008)
SELECT SUM(Passed + 0) PASS , SUM(1 - Passed) FAIL
I am adding 0 to Passed in the first sum as a short hand way of converting from bit to int since you can't sum bits directly.
try:
declare #table table (columnName bit)
insert into #table values (1)
insert into #table values (1)
insert into #table values (1)
insert into #table values (1)
insert into #table values (1)
insert into #table values (0)
insert into #table values (0)
insert into #table values (0)
insert into #table values (0)
SELECT
SUM(CASE WHEN ColumnName = 1 THEN 1 ELSE 0 END) AS True1
, SUM(CASE WHEN ColumnName = 0 THEN 1 ELSE 0 END ) AS False0
from #Table
OUTPUT:
True1 False0
----------- -----------
5 4
(1 row(s) affected)
SELECT
Attribute,
Class,
SUM(CASE BitField WHEN 1 THEN 1 ELSE 0 END) AS [Pass],
SUM(CASE BitField WHEN 0 THEN 1 ELSE 0 END) AS [Fail]
FROM
Table
GROUP BY
Attribute,
Class
Another option would be
SELECT Attribute, Class
COUNT(CASE WHEN ColumnName = 1 THEN 1 END) Pass,
COUNT(CASE WHEN ColumnName = 0 THEN 1 END) Fail FROM YourTable
GROUP BY Attribute, Class
there is even one more option:
SELECT
Attribute,
Class,
COUNT(BoolColumnName = 1 or NULL) Pass,
COUNT(BoolColumnName = 0 or NULL) Fail
FROM Table
GROUP BY Attribute, Class