Select hardcoded values in Informix DB - sql

I need to select hardcoded values in one column, so I will be able to join them with table in Informix DB. So I try in different variations to do something like this:
select a from ( values (1), (2), (3) ) ;
And I expect to get results:
1
2
3
I think in other DB this or some other variations that I tried would return the values. However, in Informix it does not work.
Could anyone suggest the solution working in Informix please?

Although what Gordon Linoff suggests will certainly work, there are also more compact notations available using Informix-specific syntax.
For example:
SELECT a
FROM TABLE(SET{1, 2, 3}) AS t(a)
This will generate a list of integers quite happily (and succinctly). You can use LIST or MULTISET in place of SET. A MULTISET can have repeated elements, unlike a SET; a LIST preserves order as well as allowing repeats.
Very often, you won't spot order not being preserved with simple values — just a few items in the list. Order is not guaranteed for SET or MULTISET; if order matters, use LIST.
You can find information about this in the IBM Informix 12.10 manual under Collection Constructors. No, it isn't obvious how you get to it — I started at SELECT, then FROM, then 'Selecting from a collection variable' and thence to 'Expression'; I spent a few seconds staring blankly at that, then looked at 'Constructor expressions' and hence 'Collection Constructors'.

INSERT INTO cccmte_pp ( cmte, pref, nro, eje, id_tri, id_cuo, fecha, vto1, vto2, id_tit, id_suj, id_bie, id_gru )
SELECT *
FROM TABLE (MULTISET {
row('RC', 4, 10, 2020, 1, 5, MDY(05,20,2020), MDY(05,20,2020),MDY(05,27,2020),101, 1, 96, 1 ),
row('RC', 4, 11, 2020, 1, 5, MDY(05,20,2020), MDY(05,20,2020),MDY(05,27,2020),101, 1, 96, 1 )
})
AS t( cmte, pref, nro, eje, id_tri, id_cuo, fecha, vto1, vto2, id_tit, id_suj, id_bie, id_gru )
IS SIMPLE SOLUTION FOR BULK INSERT, and SELECT PART SOLVING THE REST!
IS VERY SIMPLE! :) ENJOY

Informix requires an actual query statement. I think this will work:
select a
from (select 1 as a from systables where tabid = 1 union all
select 2 as a from systables where tabid = 1 union all
select 3 as a from systables where tabid = 1
) t;

Related

Db2 locate_in_string equivalent in PostgreSQL

while migration from DB2 to PostgreSQL, i found some views using db2's locate_in_string() function, which returns the position of a specified instance of a given substring.
For example:
LOCATE_IN_STRING('aaabaabbaaaab','b',1,3); -- returns 8, for the 3d instance of 'b'
LOCATE_IN_STRING('aaabaabbaaaab','b',1,1); -- returns 4, for the 1st instance of 'b'
Unfortunately PostgreSQLs function position() gives me only the position for the first instance.
I didn't find something similar in PostgreSQL.
Is there any alternative or workaround (maybe regex?)?
There may be a different method, this is rather brute force.
It splits the string based on the pattern you are looking for. It then adds up the length of the pieces:
select v.*,
(select coalesce(sum(length(el)), 0) + count(*) * length(v.splitter)
from unnest( (regexp_split_to_array(v.val, v.splitter))[1:v.n] ) el
) as pos
from (values ('aaabaabbaaaab', 3, 'b'), ('aaabaabbaaaab', 1, 'b')
) v(val, n, splitter);

Is there an equivalent to Oracle's BITAND() function in Postgres?

I know there is a Postgres function BIT_AND(), which is not the same thing - in fact it is the opposite of my end goal. I would like to be able to decode the results of an operation like Postgres BIT_AND() back into the original bits. I have code that does this in Oracle, like so:
select NVL(DECODE(BITAND(foo.bar, POWER (2, 1)), POWER (2, 1), 1), 0) first_bit,
NVL(DECODE(BITAND(foo.bar, POWER (2, 2)), POWER (2, 2), 1), 0) second_bit
from
(select 1234 bar from dual
union select 12345 bar from dual) foo
If the first bit of foo.bar is set, first_bit would return 1, otherwise 0, etc. I can translate everything to Postgres except BITAND(), and the only thing I've found discussing the issue online is a thread on forums.devshed.com from 2010 with zero responses - appreciate any insight.
EDIT: Answered below, thank you! Here are the tweaks I needed to make on my side to make it work, all because I'm actually dealing with up to 43 options that are coded as bits, and I really want to be able to use the power() function to make it very clear which bit I'm going for, so I had to convert data types.
select ((foo.bar & power(2,1)::bigint) > 0)::int as first_bit,
((foo.bar & power(2,43)::bigint) > 0)::int as forty_third_bit
from (select 1031 as bar union all
select 8796160131072
) foo
In Postgres, the bitwise and operator is &.
You would seem to want something like this:
select ((foo.bar & 2) > 0)::int as first_bit,
((foo.bar & 4) > 0)::int as second_bit
from (select 1234 as bar union all
select 12345
) foo;
I'm not sure why you are counting the bits from the second one, but the operator does the same thing as the Oracle function.
Here is a SQL Fiddle that better illustrates the operator.

Finding rows that don't contain numeric data in Oracle

I am trying to locate some problematic records in a very large Oracle table. The column should contain all numeric data even though it is a varchar2 column. I need to find the records which don't contain numeric data (The to_number(col_name) function throws an error when I try to call it on this column).
I was thinking you could use a regexp_like condition and use the regular expression to find any non-numerics. I hope this might help?!
SELECT * FROM table_with_column_to_search WHERE REGEXP_LIKE(varchar_col_with_non_numerics, '[^0-9]+');
To get an indicator:
DECODE( TRANSLATE(your_number,' 0123456789',' ')
e.g.
SQL> select DECODE( TRANSLATE('12345zzz_not_numberee',' 0123456789',' '), NULL, 'number','contains char')
2 from dual
3 /
"contains char"
and
SQL> select DECODE( TRANSLATE('12345',' 0123456789',' '), NULL, 'number','contains char')
2 from dual
3 /
"number"
and
SQL> select DECODE( TRANSLATE('123405',' 0123456789',' '), NULL, 'number','contains char')
2 from dual
3 /
"number"
Oracle 11g has regular expressions so you could use this to get the actual number:
SQL> SELECT colA
2 FROM t1
3 WHERE REGEXP_LIKE(colA, '[[:digit:]]');
COL1
----------
47845
48543
12
...
If there is a non-numeric value like '23g' it will just be ignored.
In contrast to SGB's answer, I prefer doing the regexp defining the actual format of my data and negating that. This allows me to define values like $DDD,DDD,DDD.DD
In the OPs simple scenario, it would look like
SELECT *
FROM table_with_column_to_search
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^[0-9]+$');
which finds all non-positive integers. If you wau accept negatiuve integers also, it's an easy change, just add an optional leading minus.
SELECT *
FROM table_with_column_to_search
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+$');
accepting floating points...
SELECT *
FROM table_with_column_to_search
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+(\.[0-9]+)?$');
Same goes further with any format. Basically, you will generally already have the formats to validate input data, so when you will desire to find data that does not match that format ... it's simpler to negate that format than come up with another one; which in case of SGB's approach would be a bit tricky to do if you want more than just positive integers.
Use this
SELECT *
FROM TableToSearch
WHERE NOT REGEXP_LIKE(ColumnToSearch, '^-?[0-9]+(\.[0-9]+)?$');
After doing some testing, i came up with this solution, let me know in case it helps.
Add this below 2 conditions in your query and it will find the records which don't contain numeric data
and REGEXP_LIKE(<column_name>, '\D') -- this selects non numeric data
and not REGEXP_LIKE(column_name,'^[-]{1}\d{1}') -- this filters out negative(-) values
Starting with Oracle 12.2 the function to_number has an option ON CONVERSION ERROR clause, that can catch the exception and provide default value.
This can be used for the test of number values. Simple set NULL when the conversion fails and filer all not NULL values.
Example
with num as (
select '123' vc_col from dual union all
select '1,23' from dual union all
select 'RV12P2000' from dual union all
select null from dual)
select
vc_col
from num
where /* filter numbers */
vc_col is not null and
to_number(vc_col DEFAULT NULL ON CONVERSION ERROR) is not null
;
VC_COL
---------
123
1,23
From http://www.dba-oracle.com/t_isnumeric.htm
LENGTH(TRIM(TRANSLATE(, ' +-.0123456789', ' '))) is null
If there is anything left in the string after the TRIM it must be non-numeric characters.
I've found this useful:
select translate('your string','_0123456789','_') from dual
If the result is NULL, it's numeric (ignoring floating point numbers.)
However, I'm a bit baffled why the underscore is needed. Without it the following also returns null:
select translate('s123','0123456789', '') from dual
There is also one of my favorite tricks - not perfect if the string contains stuff like "*" or "#":
SELECT 'is a number' FROM dual WHERE UPPER('123') = LOWER('123')
After doing some testing, building upon the suggestions in the previous answers, there seem to be two usable solutions.
Method 1 is fastest, but less powerful in terms of matching more complex patterns.
Method 2 is more flexible, but slower.
Method 1 - fastest
I've tested this method on a table with 1 million rows.
It seems to be 3.8 times faster than the regex solutions.
The 0-replacement solves the issue that 0 is mapped to a space, and does not seem to slow down the query.
SELECT *
FROM <table>
WHERE TRANSLATE(replace(<char_column>,'0',''),'0123456789',' ') IS NOT NULL;
Method 2 - slower, but more flexible
I've compared the speed of putting the negation inside or outside the regex statement. Both are equally slower than the translate-solution. As a result, #ciuly's approach seems most sensible when using regex.
SELECT *
FROM <table>
WHERE NOT REGEXP_LIKE(<char_column>, '^[0-9]+$');
You can use this one check:
create or replace function to_n(c varchar2) return number is
begin return to_number(c);
exception when others then return -123456;
end;
select id, n from t where to_n(n) = -123456;
I tray order by with problematic column and i find rows with column.
SELECT
D.UNIT_CODE,
D.CUATM,
D.CAPITOL,
D.RIND,
D.COL1 AS COL1
FROM
VW_DATA_ALL_GC D
WHERE
(D.PERIOADA IN (:pPERIOADA)) AND
(D.FORM = 62)
AND D.COL1 IS NOT NULL
-- AND REGEXP_LIKE (D.COL1, '\[\[:alpha:\]\]')
-- AND REGEXP_LIKE(D.COL1, '\[\[:digit:\]\]')
--AND REGEXP_LIKE(TO_CHAR(D.COL1), '\[^0-9\]+')
GROUP BY
D.UNIT_CODE,
D.CUATM,
D.CAPITOL,
D.RIND ,
D.COL1
ORDER BY
D.COL1

SQL Using ORDER BY with UNION doesn't sort numbers correctly (e.g. 10 before 8)

I've tried looking for the answer, and read many threads on this site, but still can't find the answer I'm looking for.
I am trying to sort a series of numbers that are real look-ups and also one * which isn't, I can sort fine when I don't need to add the fake * but not after.
I have tried
SELECT DISTINCT MasterTable.ClassName, MasterTable.ClassYear
FROM MasterTable
UNION ALL
SELECT DISTINCT "*" As [ClassName], "1" As [ClassYear]
FROM MasterTable
ORDER BY MasterTable.ClassYear;
And
SELECT DISTINCT MasterTable.ClassName, MasterTable.ClassYear
FROM (
SELECT DISTINCT MasterTable.ClassName, MasterTable.ClassYear FROM MasterTable
UNION
SELECT DISTINCT "*" As [ClassName], "1" As [ClassYear] FROM MasterTable
)
ORDER BY MasterTable.ClassYear;
But both return the ClassYear as 1, 10, 12, 8... rather than 1, 8, 10, 12....
Any help would be much appreciated,
Thanks :)
MasterTable.ClassYear is varchar so it will sort as a string.
You'll have to convert it in the query or fix the column type.
For the 2nd clause, you also need only:
SELECT "*" As [ClassName], "1" As [ClassYear] --No FROM MasterTable
However, you can "cheat" and do this. Here 1 will be int and will force a conversion to int from the 1st clause because
SELECT "*" As [ClassName], 1 As [ClassYear] --force int. And fixed on edit
UNION ALL
SELECT DISTINCT MasterTable.ClassName, MasterTable.ClassYear
FROM MasterTable
ORDER BY ClassYear; --no table ref needed
It's property sorting those values as strings. If you want them in numerical order, try something like Cast(MasterTable.ClassYear AS int), either in the select or in the order by, or both, depending on how you end up structuring your query.
And instead of SELECT ..., "1" As [ClassYear], write SELECT ..., 1 As [ClassYear].
You are returning the year as a string, not a number. That means that it's sorted as text, not numerically.
Either return the year as a number, or convert the value into a number when sorting it.

Searching Technique in SQL (Like,Contain)

I want to compare and select a field from DB using Like keyword or any other technique.
My query is the following:
SELECT * FROM Test WHERE name LIKE '%xxxxxx_Ramakrishnan_zzzzz%';
but my fields only contain 'Ramakrishnan'
My Input string contain some extra character xxxxxx_Ramakrishnan_zzzzz
I want the SQL query for this. Can any one please help me?
You mean you want it the other way round? Like this?
Select * from Test where 'xxxxxx_Ramakrishnan_zzzzz' LIKE '%' + name + '%';
You can use the MySQL functions, LOCATE() precisely like,
SELECT * FROM WHERE LOCATE("Ramakrishnan",input) > 0
Are the xxxxxx and zzzzz bits always 6 and 5 characters? If so, then this is doable with a bit of string cutting.
with Test (id,name) as (
select 1, 'Ramakrishnan'
union
select 2, 'Coxy'
union
select 3, 'xxxxxx_Ramakrishnan_zzzzz'
)
Select * from Test where name like '%'+SUBSTRING('xxxxxx_Ramakrishnan_zzzzz', 8, CHARINDEX('_',SUBSTRING('xxxxxx_Ramakrishnan_zzzzz',8,100))-1)+'%'
Results in:
id name
1 Ramakrishnan
3 xxxxxx_Ramakrishnan_zzzzz
If they are variable lengths, then it will be a horrible construction of SUBSTRING,CHARINDEX, REVERSE and LEN functions.