update order column in a table but maintain the order - sql-server

i have a table
id | title | F_ID | order
----------------------------
1 | test 1| 1 | 44
2 | test 3| 1 | 3
3 | test 4| 1 | 1
4 | test 5| 2 | 1
i want to update order column to +10 for all rows that have F_ID 1 but keep the order
the result need to be
id | title | F_ID | order
----------------------------
1 | test 1| 1 | 30
2 | test 3| 1 | 20
3 | test 4| 1 | 10
4 | test 5| 2 | 1
i can insert all rows that i want to update to temp table
and then loop the rows and update every row in the real table by [id].
maybe there is a better option?

I think this should work:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table test (id int, title varchar(49), F_ID int, [order] int)
insert test values
(1 , 'test 1', 1, 44),
(2 , 'test 3', 1, 3),
(3 , 'test 4', 1, 1),
(4 , 'test 5', 2, 1)
Query 1:
update test
set [order] = new_order
from test t
inner join (
select
id,
new_order = ROW_NUMBER() over (partition by f_id order by [order]) * 10
from test t
where f_id = 1
) t2
on t.id = t2.id
Results:
Query 2:
select * from test
Results:
| ID | TITLE | F_ID | ORDER |
|----|--------|------|-------|
| 1 | test 1 | 1 | 30 |
| 2 | test 3 | 1 | 20 |
| 3 | test 4 | 1 | 10 |
| 4 | test 5 | 2 | 1 |

Well there might be a better solution then this but you can try this by using recursive CTE.
;WITH updCTE
AS
(
SELECT 30 AS YourOrder, 1 AS id
UNION ALL
SELECT YourOrder - 10 AS YourOrder, id + 1 AS id
FROM updCTE
WHERE YourOrder > 1
)
UPDATE YourTable
SET [order] = YourOrder
FROM updCTE
JOIN YourTable ON updCTE.id = YourTable.id
WHERE YourTable.F_ID = 1
ORDER BY YourTable.id

Related

Summarizing a column in SQL Server after the creation of Pivot table

I cannot summarize numbers in the table (SQL-Server) after pivoting and I will be very grateful for your advice.
Better if I explain the problem on the example:
Existing table:
+-------+-----------+-----------+-------------------+
| # | $$$$$ | Fire | Water |
+-------+-----------+-----------+-------------------+
| 1 | 5 | 1 | 5 |
| 1 | 4 | 1 | 5 |
| 1 | 10 | 1 | 5 |
| 2 | 3 | 3 | 8 |
| 2 | 4 | 3 | 8 |
+-------+-----------+-----------+-------------------+
Desired output:
+-------+-----------+-----------+-------------------+
| # | $$$$$ | Fire | Water |
+-------+-----------+-----------+-------------------+
| 1 | 19 | 1 | 5 |
| 2 | 7 | 3 | 8 |
+-------+-----------+-----------+-------------------+
I tend to believe that I already tried all the solutions I found with summarizing and grouping by, but it was not solved, so I rely on you. Thanks in advance. The code I used to create the table:
WITH Enerc AS
(
SELECT
a1.[#],
a1.[$$$$$],
a2.[cause_of_loss]
FROM
data1 AS a1
LEFT JOIN
data2 AS a2 ON a1.[id] = a2.[id]
)
SELECT *
FROM Enerc
PIVOT
(SUM(gross_claim) FOR [cause_of_loss] IN ([Fire], [Water])) AS PivotTable;
No need to pivot. Your desired result should be got by grouping and using SUM:
SELECT
a1.[#],
SUM(a1.[$$$$$]),
a1.[Fire]
a1.[Water]
from data1 as a1
group by a1.[#], a1.[Fire], a1.[Water]
Let me show an example:
DECLARE #Hello TABLE
(
[#] INT,
[$$$$$] INT,
[Fire] INT,
[Water] INT
)
INSERT INTO #Hello
(
#,
[$$$$$],
Fire,
Water
)
VALUES
( 1, -- # - int
5, -- $$$$$ - int
1, -- Fire - int
5 -- Water - int
)
, (1, 4, 1, 5)
, (1, 10, 1, 5)
, (2, 3, 3, 8)
, (2, 4, 3, 8)
SELECT
h.#,
SUM(h.[$$$$$]),
h.Fire,
h.Water
FROM #Hello h
GROUP BY h.#, h.Fire, h.Water
try group by after the pivot.
With Enerc as
(SELECT
a1.[#],
a1.[$$$$$],
a2.[cause_of_loss]
from data1 as a1
left join data2 as a2
on a1.[id] = a2.[id]
)
select *
into tmp
from Enerc
PIVOT
(sum(gross_claim)
FOR [cause_of_loss] in (
[Fire], [Water]))
as PivotTable
select [#], sum([$$$$$])as [$$$$$], Fire, Water
from #tmp
group by [#],Fire, Water
EDIT: in case of permission denied:
With Enerc as
(SELECT
a1.[#],
a1.[$$$$$],
a2.[cause_of_loss]
from data1 as a1
left join data2 as a2
on a1.[id] = a2.[id]
),phase2 as(
select *
from Enerc
PIVOT
(sum(gross_claim)
FOR [cause_of_loss] in (
[Fire], [Water]))
as PivotTable)
select [#], sum([$$$$$])as [$$$$$], Fire, Water
from phase2
group by [#],Fire, Water

Select recursive in a CTE SQL query

I have a table with unique KEY (UserID and Type)
UserID | Type | Column1 | Column2
----------------------------
1 | 1 | *NULL* | 1
1 | 2 | ABC | *NULL*
1 | 3 | *NULL* | 2
2 | 1 | *NULL* | 1
2 | 2 | CDE | *NULL*
3 | 1 | *NULL* | 3
3 | 2 | DTE | *NULL*
I am trying to build a query for searching all Users IDs contains:
(Type=1 AND Column2=1) AND (Type=3 AND Column2=2)
This question has nothing to do with recursive CTEs. You can solve it with aggregation and a having clause:
select userid
from t
where (Type = 1 AND Column2 = 1) OR (Type = 3 AND Column2 = 2)
group by userid
having count(distinct type) = 2;
With CTE(userid)
AS
(
SELECT userid
FROM t
WHERE (Type = 1 AND Column2 = 1)
)
SELECT userid
FROM CTE
WHERE EXISTS(
SELECT 1
FROM CTE
WHERE Type = 3 AND Column2 = 2 )

Get the last n occurences of each value of a group

Let's say I have a table named tableA having a data of
| col1 | col2 |
| 1 | 5 |
| 1 | 6 |
| 1 | 7 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
| 3 | 3 |
| 3 | 2 |
| 3 | 1 |
Then what I would like to get is the last 2 occurrences of each unique value of col1. The result would be
| col1 | col2 |
| 1 | 6 |
| 1 | 7 |
| 2 | 3 |
| 2 | 4 |
| 3 | 2 |
| 3 | 1 |
Is there a single query to get this result?
You can use ROW_NUMBER
WITH CTE AS(
SELECT *, rn = ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col2 DESC)
FROM tbl
)
SELECT
col1, col2
FROM CTE
WHERE rn <= 2
Just expanding on Felix's answer, assuming there's an ID column: http://www.sqlfiddle.com/#!3/04a5e/3/0
WITH CTE AS(
SELECT *, rn = ROW_NUMBER() OVER(PARTITION BY cola ORDER BY id DESC)
FROM ta
)
SELECT
cola, colb
FROM CTE
WHERE rn <= 2
order by id
Need to reorder by ID to keep the correct order, plus ordering in the row_number() by the ID because col2 isn't always incremental.

Distinct 2 field AS one column SQL SERVER

can i SELECT distinct 2 fields (provfrom, provto) on table AS one column
with condition :
- values of 2 fields is never same in one row
- values in field provfrom can be inside field provto but in different row
- values in field provto can be inside field provfrom but in different row
example :
i have 2 column as below
-------------------------
| provfrom | provto |
-------------------------
| 2 | 4 |
| 3 | 7 |
| 3 | 7 |
| 5 | 2 |
| 5 | 2 |
| 7 | 2 |
| 7 | 2 |
| 1 | 5 |
| 2 | 5 |
| 2 | 8 |
| 5 | 8 |
-------------------------
the result that i want by disticnt is as below
-------------
| prov |
-------------
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 7 |
| 8 |
-------------
Can i do this in sql server?
i try to found out by explore google, but not found it
Thanks
You can use Union keyword which will give distinct elements from Both Tables
select provfrom from mytable
union
select provTo from mytable
You can either do this with a union or by using apply, the apply has less IO so I would go with the apply query.
create table #temp
(
provfrom tinyint,
provto tinyint
);
insert into #temp (provfrom, provto)
values (2,4),(3,7),(3,7),
(5,2),(5,2),(7,2),
(7,2),(1,5),(2,5),
(2,8),(5,8);
set statistics io on;
select distinct
a.provfromto
from #temp as t
cross apply (values (t.provfrom),(t.provto)) as a(provfromto);
select provfrom from #temp
union
select provTo from #temp
set statistics io off;
drop table #temp;
Try this:
select t.prov
from
(select provfrom as prov
from yourtable
union
select provto
from yourtable) as t
order by t.prov
UNION function apply a distinct clause, so you'll get all value per one occurence.
The external query about ordering your result set

SQL Server 2005 T-SQL Problem: Need help in omitting records

Good day!
I need help in writing a query.. I have records in a table below.. The condition would be no records should be displayed if the succeeding records' new_state was repeated from the previous records(new_state) and if it is changed in the same date..
here record_id 1 has gone through the ff states: 0->1->2->1->3->4->3 in the same day.. state 1 was changed to state 2 then back to state 1 again (id 2 & 3 would not be displayed).. same with state 3 (id 5 & 6 would not be displayed)..
id | record_id| date_changed | old_state | new_state |
1 | 1 | 2009-01-01 | 0 | 1 |
2 | 1 | 2009-01-01 | 1 | 2 | not displayed
3 | 1 | 2009-01-01 | 2 | 1 | not displayed
4 | 1 | 2009-01-01 | 1 | 3 |
5 | 1 | 2009-01-01 | 3 | 4 | not displayed
6 | 1 | 2009-01-01 | 4 | 3 | not displayed
so the result would display only 2 records for record_id=1..
id | record_id| date_changed | old_state | new_state |
1 | 1 | 2009-01-01 | 0 | 1 |
4 | 1 | 2009-01-01 | 1 | 3 |
Here's the code for table creation and data:
IF OBJECT_ID('TempDB..#table','U') IS NOT NULL
DROP TABLE #table
CREATE TABLE #table
(
id INT identity primary key,
record_id INT,
date_changed DATETIME,
old_state INT,
new_state INT
)
INSERT INTO #table(record_id,date_changed,old_state,new_state)
SELECT 1,'2009-01-01',0,1 UNION ALL --displayed
SELECT 1,'2009-01-01',1,2 UNION ALL --not displayed
SELECT 1,'2009-01-01',2,1 UNION ALL --not displayed
SELECT 1,'2009-01-01',1,3 UNION ALL --displayed
SELECT 1,'2009-01-01',3,4 UNION ALL --not displayed
SELECT 1,'2009-01-01',4,3 --not displayed
INSERT INTO #table(record_id,date_changed,old_state,new_state)
SELECT 3,'2009-01-01',0,1 UNION ALL --displayed
SELECT 3,'2009-01-01',1,2 UNION ALL --not displayed
SELECT 3,'2009-01-01',2,3 UNION ALL --not displayed
SELECT 3,'2009-01-01',3,4 UNION ALL --not displayed
SELECT 3,'2009-01-01',4,1 --not displayed
SELECT * FROM #table
I would appreciate any help..
Thanks
For clarity regarding record_id=3.. Given this table:
id | record_id| date_changed | old_state | new_state |
7 | 3 | 2009-01-01 | 0 | 1 |
8 | 3 | 2009-01-01 | 1 | 2 | not displayed
9 | 3 | 2009-01-01 | 2 | 3 | not displayed
10 | 3 | 2009-01-01 | 3 | 4 | not displayed
11 | 3 | 2009-01-01 | 4 | 1 | not displayed
when running the query for record_id=3, the table result will be:
id | record_id| date_changed | old_state | new_state |
7 | 3 | 2009-01-01 | 0 | 1 |
Thanks!
UPDATE (12/2/2009):
Special scenario
id | record_id| date_changed | old_state | new_state |
1 | 4 | 2009-01-01 | 0 | 1 | displayed
2 | 4 | 2009-01-01 | 1 | 2 | displayed
3 | 4 | 2009-01-01 | 2 | 3 | not displayed
4 | 4 | 2009-01-01 | 3 | 2 | not displayed
5 | 4 | 2009-01-01 | 2 | 3 | displayed
6 | 4 | 2009-01-01 | 3 | 4 | not displayed
7 | 4 | 2009-01-01 | 4 | 3 | not displayed
where new_state 3 appears on id 3,5 and 7.. id 3 would not be displayed since it is between id 2 and id 4 which have the same new_state(3).. Then id 5 should be displayed since there is no existing new_state 3 yet..
code snippet:
IF OBJECT_ID('TempDB..#tablex','U') IS NOT NULL
DROP TABLE #tablex
CREATE TABLE #tablex
(
id INT identity primary key,
record_id INT,
date_changed DATETIME,
old_state INT,
new_state INT
)
INSERT INTO #tablex(record_id,date_changed,old_state,new_state)
SELECT 4,'2009-01-01',0,1 UNION ALL --displayed
SELECT 4,'2009-01-01',1,2 UNION ALL --displayed
SELECT 4,'2009-01-01',2,3 UNION ALL --not displayed
SELECT 4,'2009-01-01',3,2 UNION ALL --not displayed
SELECT 4,'2009-01-01',2,3 UNION ALL --displayed
SELECT 4,'2009-01-01',3,4 UNION ALL --not displayed
SELECT 4,'2009-01-01',4,3 --not displayed
I think the sequence in building the result is important..
Thanks!
SELECT A.*
/*
A.ID, A.old_state, a.new_state,
B.ID as [Next], b.old_state, b.new_state,
C.ID as [Prev], c.old_state, c.new_state
*/
FROM #table A LEFT JOIN
#table B ON A.ID = (B.ID - 1)
LEFT JOIN #table C ON (A.ID - 1) = C.ID
-- WHERE A.old_State <> B.new_State AND A.new_State <> C.old_State
WHERE A.record_id = 1
AND A.old_State <> COALESCE(B.new_State, -1)
AND A.new_State <> COALESCE(C.old_State, -1)
EDIT: I guess, what OP needs is that the remaining record should be selected except those where current record's old state is not the same as next record's new state (kind of an undo operation in records) and current record's new state should not be same as previous record's old state.
Following steps to get to the result
select all items that should not appear in the result.
left join these with the original table and select only those records that don't match a should not appear record.
.
;WITH cte_table (master_id, master_state, id, record_id, old_state, new_state, level) AS
(
SELECT id, old_state, id, record_id, old_state, new_state, 1
FROM #table
UNION ALL
SELECT master_id, master_state, #table.id, #table.record_id, #table.old_state, #table.new_state, level + 1
FROM cte_table
INNER JOIN #table ON cte_table.new_state = #table.old_state
AND cte_table.record_id = #table.record_id
AND cte_table.id < #table.id
AND cte_table.master_state < #table.old_state
)
SELECT master_id, t1.*, level
INTO #result
FROM #table t1
INNER JOIN (
SELECT master_id, min_child_id = MIN(id), level
FROM cte_table
GROUP BY master_id, level
) t2 ON t2.min_child_id = t1.id
SELECT t1.*
FROM #table t1
LEFT OUTER JOIN (
SELECT r1.id
FROM #result r1
INNER JOIN (
SELECT r1.master_id
FROM #result r1
INNER JOIN #result r2 ON r2.new_state = r1.old_state
AND r2.master_id = r1.master_id
WHERE r1.level = 1
) r2 ON r2.master_id = r1.master_id
) r1 ON r1.id = t1.id
WHERE r1.id IS NULL
AND t1.old_state < t1.new_state
ORDER BY 1, 2, 3

Resources