Assign ID to each row in Microsoft sql server view - sql

Lets say I have a table like this:
create table MyTable (
Myname varchar (10) primary key not null
)
and a few row of data like:
insert into MyTable values ('john');
insert into MyTable values ('Brad');
insert into MyTable values ('James');
insert into MyTable values ('Anna');
insert into MyTable values ('Eric');
insert into MyTable values ('Hossein');
I want to create a view that assign an ID to each row,
I have used the select statement below :
select rank() OVER (ORDER BY Myname) as ID, MyTable.Myname
from MyTable
order by ID
The results is quite acceptable, But the problem come out when I try to create view
create view myview as
select rank() OVER (ORDER BY Myname) as ID, MyTable.Myname
from MyTable
order by ID
My questions are:
1- how can I create the view from the select statement mentioned above?
2- Is there any alternative way that I can use?

order by is not allowed in a view unless you use top. As per the documentation:
The SELECT clauses in a view definition cannot include the following:
An ORDER BY clause, unless there is also a TOP clause in the select list of the SELECT statement
So, your statement is fine without the order by:
create view myview as
select rank() OVER (ORDER BY Myname) as ID, MyTable.Myname
from MyTable ;
Even if you include the order by with a top, the results are not guaranteed in a particular order. You can only guarantee that by using order by the outer query.

Related

Change value of duplicated rows

There is a table with tow columns(ID, Data) and there are 3 rows with same value.
ID Data
4 192.168.0.22
4 192.168.0.22
4 192.168.0.22
Now I want to change third row DATA column. In update SQL Server Generate an error that I ca not change the value.
I can delete all 3 rows. But I can not delete third row separately.
This table is for a software that I bought and I changed the third Server IP.
You can try the following query
create table #tblSimilarValues(id int, ipaddress varchar(20))
insert into #tblSimilarValues values (4, '192.168.0.22'),
(4, '192.168.0.22'),(4, '192.168.0.22')
Use Below query if you want to change all rows
with oldData as (
select *,
count(*) over (partition by id, ipaddress) as cnt
from #tblSimilarValues
)
update oldData
set ipaddress = '192.168.0.22_1'
where cnt > 1;
select * from #tblSimilarValues
Use Below query if you want to skip firs row
;with oldData as (
select *,
ROW_NUMBER () over (partition by id, ipaddress order by id, ipaddress) as cnt
from #tblSimilarValues
)
update oldData
set ipaddress = '192.168.0.22_2'
where cnt > 1;
select * from #tblSimilarValues
drop table #tblSimilarValues
You can find the live demo live demo here
Since there is no column that allows us to distinguish these rows from each other, there's no "third row" (nor a first or second one for that matter).
We can use a ROW_NUMBER function to apply arbitrary row numbers to these rows, however, and if we place that in a CTE, we can apply DELETE/UPDATE actions via the CTE and use the arbitrary row numbers:
declare #t table (ID int not null, Data varchar(15))
insert into #t(ID,Data) values
(4,'192.168.0.22'),
(4,'192.168.0.22'),
(4,'192.168.0.22')
;With ArbitraryAssignments as (
select *,ROW_NUMBER() OVER (PARTITION BY ID, Data ORDER BY Data) as rn
from #t
)
delete from ArbitraryAssignments where rn > 2
select * from #t
This produces two rows of output - one row was deleted.
Note that I say that the ROW_NUMBER is arbitrary. One of the expressions in both the PARTITION BY and ORDER BY clauses is the same. By definition, then, we know that no real ORDER is defined by this (because all rows within the same partition, by definition, have the same value for that expression).
In this case ID columns allows duplicate value which is wrong, ID should be unique.
Now what you can do is create a new column make that unique or Primary Key or change the duplicate values of ID column and make it Unique/Primary key.
Now as per your Unique key/Primary key you can update DATA column value by query as below:
UPDATE <Table Name>
SET DATA = 'new data'
WHERE ID = 3;

Remove duplicates from table in bigquery

I found duplicates in my table by doing below query.
SELECT name, id, count(1) as count
FROM [myproject:dev.sample]
group by name, id
having count(1) > 1
Now i would like to remove these duplicates based on id and name by using DML statement but its showing '0 rows affected' message.
Am i missing something?
DELETE FROM PRD.GPBP WHERE
id not in(select id from [myproject:dev.sample] GROUP BY id) and
name not in (select name from [myproject:dev.sample] GROUP BY name)
I suggest, you create a new table without the duplicates. Drop your original table and rename the new table to original table.
You can find duplicates like below:
Create table new_table as
Select name, id, ...... , put our remaining 10 cols here
FROM(
SELECT *,
ROW_NUMBER() OVER(Partition by name , id Order by id) as rnk
FROM [myproject:dev.sample]
)a
WHERE rnk = 1;
Then drop the older table and rename new_table with old table name.
Below query (BigQuery Standard SQL) should be more optimal for de-duping like in your case
#standardSQL
SELECT AS VALUE ANY_VALUE(t)
FROM `myproject.dev.sample` AS t
GROUP BY name, id
If you run it from within UI - you can just set Write Preference to Overwrite Table and you are done
Or if you want you can use DML's INSERT to new table and then copy over original one
Meantime, the easiest way is as below (using DDL)
#standardSQL
CREATE OR REPLACE TABLE `myproject.dev.sample` AS
SELECT * FROM (
SELECT AS VALUE ANY_VALUE(t)
FROM `myproject.dev.sample` AS t
GROUP BY name, id
)

How to add a column with specific values to an existing database table

I needed an advice regarding a SQL statement that has to run with DB2 and Oracle.
Some time ago a database table has been set up without an ID column. Adding the ID column is not the problem but I absolutely need to fill it with the row number of each row.
I found out, that rank() would be perfect but here I'm not able to select for specific values because then I always get the value '1'.
When I set up an intermediate table as described below, I output all data, that I need
WITH MY_TEMP_TABLE AS
(
SELECT RANK() OVER (ORDER BY CODE ASC) MY_ROW, CODE, LAND
FROM SECOND_TABLE
)
SELECT *
FROM SECOND_TABLE
INNER JOIN MY_TEMP_TABLE ON SECOND_TABLE.CODE=MY_TEMP_TABLE.CODE
How is it possible to update the ID column in the database table (here: SECOND_TABLE) with the values in MY_ROW?
Thanks a lot...
Use row_number() instead of rank():
WITH MY_TEMP_TABLE AS
(
SELECT row_number() OVER (ORDER BY CODE ASC) MY_ROW, CODE, LAND
FROM SECOND_TABLE
)
SELECT *
FROM SECOND_TABLE
INNER JOIN MY_TEMP_TABLE ON SECOND_TABLE.CODE=MY_TEMP_TABLE.CODE

Get value of a specific column of a row without primary key

This is purely out of curiosity.
create table test (ename varchar(50))
insert into test values ('abcd')
insert into test values ('pqrs')
insert into test values ('lmno')
insert into test values ('xxxx')
insert into test values ('tops')
I want the value of 3rd row from this table in a variable. i.e "lmno"
If I do this :
Declare #value varchar(50)
Select #value = ename from
(
select Row_number() over(order by ename) Rowno, * from test
) X where Rowno=3
print #value
I will get pqrs.
I cannot use this:
Declare #value varchar(50)
Select #value = ename from
(
select Row_number() over(order by 1) Rowno, * from test
) X where Rowno=3
because
Windowed functions do not support integer indices as ORDER BY clause
expressions.
Any options?
EDIT :
If I query it as
Select * from test
I do get records in the order in which they were inserted. That means somewhere there is a record as to how they were inserted. I just want to capture this sequence.
You are making a very very poor assumption about RDBMS's. The order that a RDBMS stores records, or they order they are written to the table is 100% absolutely inconsequential. It means nothing. It's arbitrary and you can't rely on it.
You will need to either add a new column to be the 'order' that you desire, or you will have to better define why you want pqrs in your recordset since 3rd record is meaningless in this sense.
To your edit: There is no record of the order which the records were inserted. There is an order by which the records are returned to the record set, and that they naturally lay in the DB's structure underneath, but it is arbitrary. The reason you get them back in the order in which they were written is because you have a tiny little table on a RDBMS that stores data in a single spot. This fails as soon as you scale your architecture up. You can not and should never ever rely on the order that your RDBMS retrieves records.
Let's look at it step by step.
select ename from test order by ename;
This orders by ename.
select ename from test order by 1;
Here 1 is an alias for the 1st element in your select clause, which is ename. So you order by ename again.
select Row_number() over(order by ename) Rowno, * from test
The row_number function works on records ordered by ename.
select Row_number() over(order by 1) Rowno, * from test
What is 1 supposed to mean here? We are inside an over clause and there is no first element the 1 could refer to. So it is not allowed to use a number here (it would only be confusing, as it could only mean a literal 1 for every record which doesn't order anything).
As to "I do get records in the order in which they were inserted. That means somewhere there is a record as to how they were inserted. I just want to capture this sequence.": No, that isn't the case. Right now you happen to get the records in the order they were inserted, but this is in no way guaranteed. The only way to guarantee an order is to have fields to represent the desired order and use them in ORDER BY.
Try This code
create table test (ename varchar(50))
insert into test values ('abcd')
insert into test values ('pqrs')
insert into test values ('lmno')
insert into test values ('xxxx')
insert into test values ('tops')
SELECT *FROM (
SELECT ROW_NUMBER() over (order by HH) AS RNO,ename FROM (SELECT ENAME,'' AS HH FROM test) T)T1
WHERE RNO=3
WITH MyCte AS
(
SELECT *, row_number() OVER(ORDER BY (SELECT 0)) ID FROM test
)
SELECT *
FROM MyCte
WHERE ID = 3
Try:
create table #test (ename varchar(50))
insert into #test values ('abcd')
insert into #test values ('pqrs')
insert into #test values ('lmno')
insert into #test values ('xxxx')
insert into #test values ('tops')
CREATE TABLE #Temp(RowID INT PRIMARY KEY IDENTITY(1,1), ename VARCHAR(10))
INSERT INTO #temp(ename)
SELECT ename from #test
SELECT T2.*
FROM #temp T1
JOIN #test T2 ON T1.ename = T2.ename
WHERE T1.RowID = 3

Dynamically numbering distinct sql rows in select statement

How would I dynamically number rows in a query similar to this:
Select distinct name from #table where %rules
When I add ROW_NUMBER() OVER() I lose my distinct property, and it returns every element in table, with a unique row number.
Select distinct ROW_NUMBER OVER(order by name), name from #table where %rules
I don't want to create a temporary table, otherwise I would make a primary key for the temporary table and have it insert row numbers that way.
Thanks in advance!
Use like this.
select ROW_NUMBER() OVER(order by name), * from
(Select distinct name from #table where %rules) as mytable