sybase - update column to be identity, ordered by certain values - sql

I want to update the sequence column below to be an IDENTITY column in future, and the current rows must be updated to be ordered by update_time ascending.
How do I do this in Sybase? Simplified example of what I have below.
Current table:
SEQUENCE | UPDATE_TIME | DATA
null | 2016-01-01 | x
null | 2013-01-01 | y
null | 2015-01-01 | z
Desired table:
SEQUENCE | UPDATE_TIME | DATA
3 | 2016-01-01 | x
1 | 2013-01-01 | y
2 | 2015-01-01 | z

I did this by joining the table onto itself but with 1 additional ID row. This additional row is created using the ROW_NUMBER function by ordering the update_time ascending. Something like...
UPDATE myTable SET update_seq = tmp.ID
FROM myTable a INNER JOIN (
SELECT update_time, data, ROW_NUMBER() OVER (ORDER BY update_seq ASC) as ID from myTable tmp
on a.update_time = tmp.update_time
and a.data = tmp.data

On Sybase ASA you can numerate column using that update:
update [table_name]
set [SEQUENCE]=number(*)
order by [UPDATE_TIME]

Related

Can I join each row of table1 to a unique row of table 2?

I was hoping to query in all the rows of a table that has its ids starting at some number, and update each row of the original table with a one to one of the second table.
For example:
normal
id | fk_test_id
----------------
1 | null
2 | null
3 | null
starts_after
id |
----
12 |
13 |
14 |
What UPDATE can I use to make normal look like this:
id | fk_test_id
----------------
1 | 12
2 | 13
3 | 14
I tried:
UPDATE normal SET fk_test_id = starts_after.id FROM starts_after; which just joins on the first row of starts_after.
UPDATE normal SET fk_test_id = (SELECT id FROM starts_after ORDER BY random() LIMIT 1); Where the subquery only executes once.
Filtering the subquery by which fk_test_ids are already chosen, but it only executes on the pre-updated data.
If you added record with specific order in to starts_after you can use below query:
update normal n
set fk_test_id = tmp.id
from (select id,
row_number() over (order by id)
from starts_after) tmp
where tmp.row_number = n.id;
I ordered by id from starts_after table (ASC) and create range of record with row num:
id | row_number
----------------
12 | 1
13 | 2
14 | 3
After that i join two table and update records

SQL: How can I pick a cell value from one table as a condition to select another table

Hi I'm a new learner of SQL. How can I realize this process in SQL or perhaps with python if needed:
First, from table1, I randomly selected two results:
SELECT TOP 2 id, date
FROM table 1
WHERE date >= 2 AND date <= 6
ORDER BY RAND(CHECKSUM(*) * RAND())
+-----------+
| table1 |
+-----------+
| id | date |
+----+------+
| x | 3 |
| y | 4 |
+----+------+
I need to use the value x and y as conditions to display another table. For instance, using x, I can:
SELECT id, date
FROM table1
WHERE date >= 2 AND date <= 6 AND id = 'x'
ORDER BY date ASC
+-----------+
| table2 |
+-----------+
| id | date |
+----+------+
| x | 3 |
| x | 4 |
| x | 5 |
| x | 6 |
| x | 6 |
+----+------+
What I need is to get the length of table2 without duplication on date. For instance, table2 has 5 rows, but last two duplicate in date. So the final answer is 4 rows.
For id = y, I have to do the same thing (say table3) and compare the length of table3 and table2 to see if consistent.
If yes, then return the length (say, 4 rows); If no, then go back to table1 and select another two id (say, z and y).
I was thinking to use python to select value or create variables, then use python variables in SQL. But it is too much for a new learner. I really appreciate it if someone could help me out this process.
You can use subqueries with IN clause
Here is too a Version with two diemsnions, maybe this will help also
CREATE TABLE table1 ([id] varchar(2),[date] int)
GO
✓
SELECT id, date FROM table1
where date >= 2 and date <= 6
and id IN (
SELECT TOP 2 id FROM table1
WHERE date >= 2 and date <= 6
ORDER BY RAND(CHECKSUM(*) * RAND())
)
ORDER BY date ASC
GO
id | date
:- | ---:
SELECT id, date FROM table1
WHERE EXISTS (SELECT 1
FROM (
SELECT TOP 2 id,[date] FROM table1
WHERE date >= 2 and date <= 6
ORDER BY RAND(CHECKSUM(*) * RAND())) AS table2
WHERE table1.[id] = table2.[id]
AND table1.[date] = table2.[date])
GO
id | date
:- | ---:
db<>fiddle here

Increment value in column in an SQL table

So i have the following case to resolve.
I have a table with the following structure and i need to do the column Comment3 incremented by 1 but not for whole the records, but only for the records that are matched based on the Tid column.
So my table looks like this
------------------------
ID | TID | COMMENT3
------------------------
101 | 715 | 1
102 | 715 | 2
103 | 715 | NULL
104 | 715 | NULL
So i need every null value in column Comment3 to get updated with the last value plus 1, based on the TID which is the reference column.
Thanks in advance.
Use a ROW_NUMBER() with the proper OVER clause:
;WITH Comment3NewRanking AS
(
SELECT
T.ID,
T.TID,
T.Comment3,
Ranking = ROW_NUMBER() OVER (PARTITION BY T.TID ORDER BY T.ID ASC)
FROM
YourTable AS T
)
UPDATE C SET
Comment3 = C.Ranking
FROM
Comment3NewRanking AS C
WHERE
C.Comment3 IS NULL
This solution assumes that whenever the IDs are set for a particular TID, they are in ascending ID order. Also assuming you want values from 1 onwards on each tier of TID (if not please supply another representative example).

How to find the earliest data that closest to the specified date?

Some business data has a create_on column to indicate the creation date, and I want to find the earliest data that closest to the specified date. How do I write the sql? I'm using postgres database.
drop table if exists t;
create table t (
id int primary key,
create_on date not null
-- ignore other columns
);
insert into t(id, create_on) values
(1, '2018-01-10'::date),
(2, '2018-01-20'::date);
-- maybe have many other data
| sn | specified-date | expected-result |
| 1 | 2018-01-09 | (1, '2018-01-10'::date) |
| 2 | 2018-01-10 | (1, '2018-01-10'::date) |
| 3 | 2018-01-11 | (1, '2018-01-10'::date) |
| 4 | 2018-01-19 | (1, '2018-01-10'::date) |
| 5 | 2018-01-20 | (2, '2018-01-20'::date) |
| 6 | 2018-01-21 | (2, '2018-01-20'::date) |
This is tricky, because you seem to want the most recent row one or before the date. But if no such row exists, you want the earliest date in the table:
with tt as (
select t.*
from t
where t.created_on <= :specified_date
order by t.created_on desc
fetch first 1 row only
)
select tt.* -- select most recent row before the date
from tt
union all
select t.* -- otherwise select most oldest row
from t
where not exists (select 1 from tt)
order by t.created_on
fetch first 1 row only;
EDIT:
You can also handle this with a single query:
select t.*
from t
order by (t.created_on <= :specified_date) desc, -- put older dates first
(case when t.created_on <= :specified_date then created_on end) desc,
created_on asc
fetch first 1 row only;
Although this looks simpler, it might actually be more expensive, because the query cannot make use of an index on (created_on). And, there is no where clause reducing the number of rows before sorting.

Delete rows except for one for every id

I have a dataset with multiple ids. For every id there are multiple entries. Like this:
--------------
| ID | Value |
--------------
| 1 | 3 |
| 1 | 4 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
| 3 | 5 |
--------------
Is there a SQL DELETE query to delete (random) rows for every id, except for one (random rows would be nice but is not essential)? The resulting table should look like this:
--------------
| ID | Value |
--------------
| 1 | 2 |
| 2 | 1 |
| 3 | 5 |
--------------
Thanks!
It doesn't look like hsqldb fully supports olap functions (in this case row_number() over (partition by ...), so you'll need to use a derived table to identify the one value you want to keep for each ID. It certainly won't be random, but I don't think anything else will be either. Something like so
This query will give you the first part:
select
id,
min(value) as minval
from
group by id
Then you can delete from your table where you don't match:
delete from
<your table> t1
inner join
(
select
id,
min(value) as minval
from
<your table>
group by id
) t2
on t1.id = t2.id
and t1.value <> t2.value
Try this:
alter ignore table a add unique(id);
Here a is the table name
This should do what you want:
SELECT ID, Value
FROM (SELECT ID, Value, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY NEWID()) AS RN
FROM #Table) AS A
WHERE A.RN = 1
I tried the given answers with HSQLDB but it refused to execute those queries for different reasons (join is not allowed in delete query, ignore statement is not allowed in alter query). Thanks to Andrew I came up with this solution (which is a little bit more circumstantial, but allows it to delete random rows):
Add a new column for random values:
ALTER TABLE <table> ADD COLUMN rand INT
Fill this column with random data:
UPDATE <table> SET rand = RAND() * 1000000
Delete all rows which don't have the minimum random value for their id:
DELETE FROM <table> WHERE rand NOT IN (SELECT MIN(rand) FROM <table> GROUP BY id)
Drop the random column:
ALTER TABLE <table> DROP rand
For larger tables you probably should ensure that the random values are unique, but this worked perfectly for me.