Cannot lookup row in database by UUID RAW(32) - sql

I have the following table:
create table Mike_Test
( Id raw(32) default sys_guid() not null primary key,
Value varchar2(80) not null unique
);
I now insert into this table:
INSERT INTO Mike_Test (VALUE) VALUES ('Blah');
I can confirm there's a new row in there:
select * from Mike_Test;
And I see:
08364fc81419429d83c9bcedb24a9a57 Blah
Now I try to SELECT that row with:
select * from Mike_Test WHERE ID='08364fc81419429d83c9bcedb24a9a57';
However, I get zero rows and zero errors. What am I doing wrong?

It's a RAW datatype, you have to query like this:
select .... where id=hextoraw('08364fc81419429d83c9bcedb24a9a57') ....

I think you might need to use the HEXTORAW function around your ID value. This function converts a hex string into the corresponding RAW value.
In other words, your query should look like the following:
select * from Mike_Test WHERE ID=HEXTORAW('08364fc81419429d83c9bcedb24a9a57');

Heh, I did some more toying and the answer is pretty silly. It seems Oracle will implicitly cast a string to a GUID (like a normal human being would expect), but the casts are case-sensitive! Which makes absolutely zero sense if you're parsing hexidecimal numbers and casing isn't relative to your base. The reason this was throwing me off was because I was using Aqua Data Studio, which for some reason displays GUIDs in all lower case.
The following is from SQLPlus, which handles the output correctly:
SQL> select * from Mike_Test;
ID
--------------------------------
VALUE
--------------------------------------------------------------------------------
4FBD50C370BC4A7F85E3DF034D120930
Blah
SQL> select * from Mike_Test WHERE ID='4fbd50c370bc4a7f85e3df034d120930';
no rows selected
SQL> select * from Mike_Test WHERE ID='4FBD50C370BC4A7F85E3DF034D120930';
ID
--------------------------------
VALUE
--------------------------------------------------------------------------------
4FBD50C370BC4A7F85E3DF034D120930
Blah
Oracle gets sillier each day I use it, I swear.

Adding to my answer (I didn't want to EDIT my original answer since this is such a tangent):
There's huge performance differences between the implicit cast I was trying to do, and the recommended HEXTORAW approach. The query plan for the implicit cast looks something like:
SELECT STATEMENT 3.0 3 37877 1 52 3 ALL_ROWS
TABLE ACCESS (FULL) 3.0 3 37877 1 52 1 TPMDBO MIKE_TEST FULL TABLE 1
And HEXTORAW is:
SELECT STATEMENT 1.0 1 15463 1 52 1 ALL_ROWS
TABLE ACCESS (BY INDEX ROWID) 1.0 1 15463 1 52 1 TPMDBO MIKE_TEST BY INDEX ROWID TABLE 1
INDEX (UNIQUE SCAN) 1.0 1 8171 1 1 TPMDBO SYS_C007969 UNIQUE SCAN INDEX (UNIQUE) 1
As you can see, the HEXTORAW approach will hit the primary key index on the table. This is because the implicit conversion will honor the "string" type of the right operand (the GUID I specify), and convert all the GUIDs in the database to strings. Definitely something to consider.

Related

Generate new ID for every new combination of column 1 and column 2

I would like to generate a new ID number for every new combination of column 1 and column 2.
For example:
ID | column 1 | column 2
1 | peter | blue
2 | mark | red
1 | peter | blue
As there will be new rows added over time, with new values, this should be able to auto-update.
I tried DENSE_RANK(), which seemed to work. But it gave an error when I put it as a statement in a calculated column, so I guess this is not possible? (Still very new to SQL).
Thanks for any help!
Error message: #1901 - Function or expression 'dense_rank()' cannot be
used in the GENERATED ALWAYS AS clause of `ProductIdentifier
EDIT:
What I basically want is to link a row to another table based on the 2 columns. I could also concatenate the two columns of course, but I read somewhere that doing this with string will be slower. It will ultimately be a big table with currently 200.000+ rows and growing to millions. Is this something I could/should do?
I don't understand. If you want column1/column2 to be unique, then they should be in their own table:
create table t12 (
t12_id int auto_increment primary key,
column1 int,
column2 int,
unique (column1, column2)
);
This gives you the unique value for the pair that you seem to want.
You can't use window functions in a generated column, as you found out. You can, however, compute the information on the fly in a view:
create view myview as
select id, column1, column2, dense_rank() over(order by column1, column2) rn
from mytable
Then you can query the view instead of the table, like:
select * from myview;

find character within a string sql

I have a string column called day with indexes of the days of week as follows
1,2,3,4,5,6,7
I want to check if for example 1 exists in the string within the column.
the logic should be like this.
select * from table where 1 is in day;
how can I achieve this with psql?
select * from table
where position('1' in day) > 0
But in general it's a bad idea to store comma separated items in a column, it will only cause you lots of trouble.
You shouldn't be storing comma separated values in the first place.
The solution using like or position() can fail if you have two-digit numbers in those values, e.g. '12,13' would be found by position('1' in day) as well.
To avoid that, convert the de-normalized value into an array, then search in the array:
select *
from the_table
where '1' = any(string_to_array(day, ','));
Online example: https://rextester.com/GEMN57014
Another way You can try to use like
PostgreSQL 9.6 Schema Setup:
CREATE TABLE T(col1 varchar(50));
INSERT INTO T VALUES ('1,2,3,4,5,6,7');
INSERT INTO T VALUES ('2,3,4,5,6,7,1');
INSERT INTO T VALUES ('5,6,7');
Query 1:
select *
from T
WHERE col1 like concat('%','1',',%') or col1 like concat('%,','1','%')
Results:
| col1 |
|---------------|
| 1,2,3,4,5,6,7 |
| 2,3,4,5,6,7,1 |

How to lookup based on ranged values

I have a table like:
id name
001to005 ABC
006to210 PQR
211to300 XYZ
This is not the final table i can make it any how i want...so i would like to lookup on this data on id and extract name like if id is in range of 001-005 then ABC and if id is in range 006-010 .... then name XYZ.
My approach would be, store id as regular expression in table like this:
id name
[0][0][1-5] ABC
[0-2][0-9][0-9] PQR
[2-3][0-9][0-9] XYZ
and then query:
select * from table where '004' ~ id
This query will return ABC which is correct but when range gets bigger my input value can lie on both 2nd and 3rd row.
For Eg:
select * from table where '299' ~ id
this query will result in 2 rows,so my question is what reg exp to use to make it more restrictive or is there any other approach to solve this:
Do not store regular expressions for simple ranges, that would be extremely expensive and cannot use an index: every single expression in the table would have to be evaluated for every query to satisfy conditions.
You could use range types like #a_horse commented. But while you don't need the added functionality for range types this simple layout is smaller and faster:
CREATE TABLE tbl (
id_lo int NOT NULL
, id_hi int NOT NULL
, name text NOT NULL
);
INSERT INTO t VALUES
( 1, 5, 'ABC')
, ( 6, 210, 'PQR')
, (211, 300, 'XYZ');
CREATE UNIQUE INDEX foo ON t (id_lo, id_hi DESC);
Two integer occupy 8 bytes, int4range value occupies 17 bytes. Size matters in tables and indexes.
Query:
SELECT * FROM tbl
WHERE 4 BETWEEN id_lo AND id_hi;
Lower (id_lo) and upper (id_hi) bounds are included in the range like your sample data suggests.
Note that range types exclude the upper bound by default.
Also assuming that leading zeros are insignificant, so we can operate with plain integer.
Related:
PostgreSQL daterange not using index correctly
Optimizing queries on a range of timestamps (two columns)
Find overlapping date ranges in PostgreSQL
To enforce distinct ranges in the table:
Preventing adjacent/overlapping entries with EXCLUDE in PostgreSQL
You still don't need a range type in the table for this:
Postgres: How to find nearest tsrange from timestamp outside of ranges?

About dual table structure in Oracle SQL *Plus

We know that "Dual" is a temporary table which exactly contains 1 column whose name is "dummy" which is of "varchar2(1)" type that has 1 single row. The value of that record is "X". The varchar2 has size of 1 which means it should not allow more than a single character.
Now my question is: If it is of varchar2 type, then why it can hold any datatype temporarily AND If we insert characters more than 1 (size), how this is possible for it (dual) to accept it ? Example:
SQL> desc dual
Name Null? Type
------------------------------- -------- ----
DUMMY VARCHAR2(1)
SQL> select sysdate from dual;
SYSDATE
---------
22-JAN-13
SQL> select 5*5 result from dual;
RESULT
---------
25
SQL> select 'Ankita' as "Name" from dual;
Name
------
Ankita
Clearly "SYSDATE" is of DATE type (not varchar2), "RESULT" is of NUMBER type (not varchar2). Also 'Ankita' is more than 1 single character, i.e., 6 characters. This should contradict the structure that varchar2 is holding only 1, and supporting 6 too..
The types and sizes of columns only come into play when you extract the data from them. It's true that if you select the dummy column, it will only give you what is in that column.
But, when you're selecting something unrelated to the column data, such as 5*5 or 'Ankita', they have no such restrictions.
I think your misunderstanding stems from your snippet:
why it can hold any datatype temporarily AND If we insert characters more than 1 (size), how this is possible for it (dual) to accept it ?
The truth is, the column doesn't accept it. Selecting 5*5 does not attempt to place that data into the table somewhere, it just evaluates it as-is. It's no different to having a table with:
users:
id
name
and performing:
select 42, 3.14159, id, name from users
For every row selected from, you will see the constant values 42 and 3.14159, alongside the data extracted from the two specified columns.

Select statement in SQLite recognizing row number

I want to write SQLite statement something like this:
SELECT * FROM Table WHERE RowNumber BETWEEN 1 AND 10;
but i don't have such column RowNumber. I have primary key in my table. But is there row number by default that i could use ?
Also i am searching info about writing more complicated SQLite statement. So if you have some links in bookmarks please share.
Thanks.
You want to use LIMIT and OFFSET
SELECT * FROM Table LIMIT 10 OFFSET 0
Which can also be expressed with the following shorthand syntax
SELECT * FROM Table LIMIT X,Y
Where X represents the offset, which is exclusive, and Y represents the quantity, so for example
SELECT * FROM Table LIMIT 50,50
Would return rows 51-100
The automatically-created rowid for a table can be accessed by a few different names. From the SQLite documentation:
Every row of every SQLite table has a 64-bit signed integer key that uniquely identifies the row within its table. This integer is usually called the "rowid". The rowid value can be accessed using one of the special case-independent names "rowid", "oid", or "_rowid_" in place of a column name.
SELECT * FROM Table WHERE ROWID BETWEEN 1 AND 10;