Firebird SQL: pass multi-row data in the query text - sql

is it possible to use an array of elements as a select statement?
I know it is possiible to get rows based on static elements like this:
SELECT 405, CAST('4D6178' AS VARCHAR(32)), CAST('2017-01-01 00:00:00' AS TIMESTAMP) FROM rdb$databas
That will give you a table select with one row.
Now I would like to get this as table with n rows, but I don't know how to achieve this. Due to the fact that firebird doesn't allow multiple select statements I cannot only append n times a selec.
Info : Firebird 2.1

Use UNION ALL clause.
https://en.wikipedia.org/wiki/Set_operations_(SQL)#UNION_operator
Select x,y,z From RDB$DATABASE
UNION ALL
Select a,b,c From RDB$DATABASE
UNION ALL
Select k,l,m From RDB$DATABASE
Notice however that this should only be used for small data. Firebird query length is limited to 64KB and even if that would not be so - abusing this method to inject lots of data would not be good.
If you really need to enter lot of similar (same structure) data rows - use Global Temporary Tables
The following discussion hopefully would give you more insights:
https://stackoverflow.com/a/43997801/976391

Related

The data types in each column don't need to be compatible between the UNION queries

I read here that to be able to use SQL UNION queries,
data types in each column must be compatible between the individual queries.
So select a, b from table1 UNION select c, d from table2, for this query to work, we need a and c data types to be compatible.
However, when I try to test that, and make table users having two columns (id int, name varchar(15)), and table calc having two values (x int, y int), and after inserting elements
(1, 'saad') into table users, and values (3, 5) into table calc, and try query select * from users union select * from calc;, it shows the results as follows without any errors:
1 | saad
3 | 5
although name and y data types is not compatible, and was supposed to cause error
Conversion failed when converting the int value 5 to data type varchar
I thought it may be browser specific behavior, so I tried this also in google chrome, but it worked without any errors also!
Can someone explain to me why?
Thanks in advance.
Edit:
I'm using MySql 5.6
With MS SQL, there's a distinction between UNION and UNION ALL.
In the case of a UNION query, each value is compared to every other value for that column across all of select clauses. This might result in fewer records in final result than exist in the original select clause results. Even if you didn't intend for it, the optimizer will compare values from a and c along with b and d to find the uinion of those two sets. That also means that the datatype if they're different goes through an implicit data conversion to sql_variant to accomplish the goal of the union request.
Since UNION ALL is just stacking the sets one on top of each other, there's less of a need to compare the values.

Is there any SQL query character limit while executing it by using the JDBC driver [duplicate]

I'm using the following code:
SELECT * FROM table
WHERE Col IN (123,123,222,....)
However, if I put more than ~3000 numbers in the IN clause, SQL throws an error.
Does anyone know if there's a size limit or anything similar?!!
Depending on the database engine you are using, there can be limits on the length of an instruction.
SQL Server has a very large limit:
http://msdn.microsoft.com/en-us/library/ms143432.aspx
ORACLE has a very easy to reach limit on the other side.
So, for large IN clauses, it's better to create a temp table, insert the values and do a JOIN. It works faster also.
There is a limit, but you can split your values into separate blocks of in()
Select *
From table
Where Col IN (123,123,222,....)
or Col IN (456,878,888,....)
Parameterize the query and pass the ids in using a Table Valued Parameter.
For example, define the following type:
CREATE TYPE IdTable AS TABLE (Id INT NOT NULL PRIMARY KEY)
Along with the following stored procedure:
CREATE PROCEDURE sp__Procedure_Name
#OrderIDs IdTable READONLY,
AS
SELECT *
FROM table
WHERE Col IN (SELECT Id FROM #OrderIDs)
Why not do a where IN a sub-select...
Pre-query into a temp table or something...
CREATE TABLE SomeTempTable AS
SELECT YourColumn
FROM SomeTable
WHERE UserPickedMultipleRecordsFromSomeListOrSomething
then...
SELECT * FROM OtherTable
WHERE YourColumn IN ( SELECT YourColumn FROM SomeTempTable )
Depending on your version, use a table valued parameter in 2008, or some approach described here:
Arrays and Lists in SQL Server 2005
For MS SQL 2016, passing ints into the in, it looks like it can handle close to 38,000 records.
select * from user where userId in (1,2,3,etc)
I solved this by simply using ranges
WHERE Col >= 123 AND Col <= 10000
then removed unwanted records in the specified range by looping in the application code. It worked well for me because I was looping the record anyway and ignoring couple of thousand records didn't make any difference.
Of course, this is not a universal solution but it could work for situation if most values within min and max are required.
You did not specify the database engine in question; in Oracle, an option is to use tuples like this:
SELECT * FROM table
WHERE (Col, 1) IN ((123,1),(123,1),(222,1),....)
This ugly hack only works in Oracle SQL, see https://asktom.oracle.com/pls/asktom/asktom.search?tag=limit-and-conversion-very-long-in-list-where-x-in#9538075800346844400
However, a much better option is to use stored procedures and pass the values as an array.
You can use tuples like this:
SELECT * FROM table
WHERE (Col, 1) IN ((123,1),(123,1),(222,1),....)
There are no restrictions on number of these. It compares pairs.

what is the maximum value we can use with IN operator in sql [duplicate]

I'm using the following code:
SELECT * FROM table
WHERE Col IN (123,123,222,....)
However, if I put more than ~3000 numbers in the IN clause, SQL throws an error.
Does anyone know if there's a size limit or anything similar?!!
Depending on the database engine you are using, there can be limits on the length of an instruction.
SQL Server has a very large limit:
http://msdn.microsoft.com/en-us/library/ms143432.aspx
ORACLE has a very easy to reach limit on the other side.
So, for large IN clauses, it's better to create a temp table, insert the values and do a JOIN. It works faster also.
There is a limit, but you can split your values into separate blocks of in()
Select *
From table
Where Col IN (123,123,222,....)
or Col IN (456,878,888,....)
Parameterize the query and pass the ids in using a Table Valued Parameter.
For example, define the following type:
CREATE TYPE IdTable AS TABLE (Id INT NOT NULL PRIMARY KEY)
Along with the following stored procedure:
CREATE PROCEDURE sp__Procedure_Name
#OrderIDs IdTable READONLY,
AS
SELECT *
FROM table
WHERE Col IN (SELECT Id FROM #OrderIDs)
Why not do a where IN a sub-select...
Pre-query into a temp table or something...
CREATE TABLE SomeTempTable AS
SELECT YourColumn
FROM SomeTable
WHERE UserPickedMultipleRecordsFromSomeListOrSomething
then...
SELECT * FROM OtherTable
WHERE YourColumn IN ( SELECT YourColumn FROM SomeTempTable )
Depending on your version, use a table valued parameter in 2008, or some approach described here:
Arrays and Lists in SQL Server 2005
For MS SQL 2016, passing ints into the in, it looks like it can handle close to 38,000 records.
select * from user where userId in (1,2,3,etc)
I solved this by simply using ranges
WHERE Col >= 123 AND Col <= 10000
then removed unwanted records in the specified range by looping in the application code. It worked well for me because I was looping the record anyway and ignoring couple of thousand records didn't make any difference.
Of course, this is not a universal solution but it could work for situation if most values within min and max are required.
You did not specify the database engine in question; in Oracle, an option is to use tuples like this:
SELECT * FROM table
WHERE (Col, 1) IN ((123,1),(123,1),(222,1),....)
This ugly hack only works in Oracle SQL, see https://asktom.oracle.com/pls/asktom/asktom.search?tag=limit-and-conversion-very-long-in-list-where-x-in#9538075800346844400
However, a much better option is to use stored procedures and pass the values as an array.
You can use tuples like this:
SELECT * FROM table
WHERE (Col, 1) IN ((123,1),(123,1),(222,1),....)
There are no restrictions on number of these. It compares pairs.

Using 'AS' Statement in MS QUERY SQL with 'UNION ALL'

My company has a dual company structure which requires that data be kept separate. We have two datasets which are identical in structure. I commonly use MS Query to write SQL using one dataset, and when I have what I want, I simply add a UNION ALL statement and repeat the SQL but replace any dataset names with the second one. It always works fine tp give me a single query combining the data from both datasets.
However, I am retrieving some date fields using the datepart function to get the year and month of the records, and I use the AS statement to name the columns.
Example: Select datepart(yyyy,receiptdate) as "Year"
While it works in the original query with one dataset, when I create the 'UNION ALL' and add the additional SQL, the column name becomes blank. The same goes for some fields that I am summarizing and renaming to have a more concise name than SUM(QUANTITY_ORDERED) -- they turn blank after the UNION ALL.
Is there a trick to renaming columns when using UNION ALL, or other suggestions?
Thanks,
Mark
If you are referring to SQL SERVER (I'm honestly not sure what ms-query is), then it should be that your column aliases are done in the first statement of your union
For example the first example below leaves column name blank while the second example provides the correct column name;
-- Example 1
Select datepart(yyyy,CURRENT_TIMESTAMP)
UNION ALL
SELECT datepart(yyyy,DATEADD(YY, -1, CURRENT_TIMESTAMP)) as "Year"
-- Example 2
Select datepart(yyyy,CURRENT_TIMESTAMP) as "Year"
UNION ALL
SELECT datepart(yyyy,DATEADD(YY, -1, CURRENT_TIMESTAMP))

How to make result set from ('1','2','3')?

I have a question, how can i make a result set making only list of values. For example i have such values : ('1','2','3')
And i want to make a sql that returns such table:
1
2
3
Thanks.
[Edit]
Sorry for wrong question.
Actually list not containing integers, but it contains strings.
I am currently need like ('aa','bb,'cc').
[/Edit]
If you want to write a SQL statement which will take a comma separate list and generate an arbitrary number of actually rows the only real way would be to use a table function, which calls a PL/SQL function which splits the input string and returns the elements as separate rows.
Check out this link for an intro to table-functions.
Alternatively, if you can construct the SQL statement programmatically in your client you can do:
SELECT 'aa' FROM DUAL
UNION
SELECT 'bb' FROM DUAL
UNION
SELECT 'cc' FROM DUAL
The best way I've found is using XML.
SELECT items.extract('/l/text()').getStringVal() item
FROM TABLE(xmlSequence(
EXTRACT(XMLType(''||
REPLACE('aa,bb,cc',',','')||'')
,'/all/l'))) items;
Wish I could take credit but alas : http://pbarut.blogspot.com/2006/10/binding-list-variable.html.
Basically what it does is convert the list to an xmldocument then parse it back out.
The easiest way is to abuse a table that is guaranteed to have enough rows.
-- for Oracle
select rownum from tab where rownum < 4;
If that is not possible, check out Oracle Row Generator Techniques.
I like this one (requires 10g):
select integer_value
from dual
where 1=2
model
dimension by ( 0 as key )
measures ( 0 as integer_value )
rules upsert ( integer_value[ for key from 1 to 10 increment 1 ] = cv(key) )
;
One trick I've used in various database systems (not just SQL databases) is actually to have a table which just contains the first 100 or 1000 integers. Such a table is very easy to create programatically, and your query then becomes:
SELECT value FROM numbers WHERE value < 4 ORDER BY value
You can use the table for lots of similar purposes.