This question already has an answer here:
Select IN on more than 2100 values
(1 answer)
Closed 8 years ago.
In Coldfusion I'm trying to do a select query on an Oracle database table that I only have read access to. I have a list (lets call it myList) of several thousand IDs that I want to do the query on.
SELECT * FROM table
WHERE userID IN (#myList#)
The issue I have is that Oracle only lets me use IN with 1000 items at a time. What is the most efficient way to approach this? Break up the list by 1000 and append the resulting queries? If so what should my code for breaking the list look like?
Thanks!
There is a function available on cflib.org called ListSplit. It splits your long list into an array of shorter lists. Once you find and run this, your query starts to look like this:
select JustTheFieldsYouNeed
from SomeTables
where 1 = 3
<cfloop array="#ArrayOfShorterLists#" index = "ThisList">
or SomeField in
(<cfqueryparam cfsqltype="cf_sql_integer" value = "#ThisList#" List = "yes"> )
</cfloop>
If you're looking to do this for ad hoc queries, this can be done with a WITH query:
WITH
UserList AS
(
SELECT 'UserID1' AS UserID FROM DUAL UNION ALL
SELECT 'UserID2' AS UserID FROM DUAL UNION ALL
...
SELECT 'UserIDX' AS UserID FROM DUAL
)
SELECT t.*
FROM table t
JOIN UserList U
ON t.UserID = U.UserID
That list in between the parentheses of the UserList WITH query can be as long as you want it to be, and can pretty easily be created with Excel (assuming that's where the list you want to check originated).
-
Example Excel formula (assuming your first value is in A2):
="SELECT '" & A2 & "' AS UserID FROM DUAL" & IF(A3="", "", " UNION ALL ")
or, if your UserID is numeric:
="SELECT " & A2 & " AS UserID FROM DUAL" & IF(A3="", "", " UNION ALL ")
(autofilling this down to the bottom of your list will create everything you need to paste in between the parentheses of that query above)
-
HOWEVER, note that this is only good for ad hoc type queries. This is not a good solution if you need to do this on an automatic basis. If this is for a more permanent solution, use temp (or permanent) tables.
Edit Starts Here
Here is some simple code that shows how to do this in ColdFusion
<cfset ids = "1,2">
<cfquery name="x" datasource="oraclesomething">
with IDList as (
select 0 id
from dual
where 1 = 2
<cfloop list="#ids#" index="ThisID">
union
select #ThisID# id
from dual
</cfloop>
)
select count(*) from some_table join IDList on someid = id
</cfquery>
<cfdump var="#x#" metainfo="no">
Related
Let me explain the question.
I have two tables, which have 3 columns with same data tpyes. The 3 columns create a key/ID if you like, but the name of the columns are different in the tables.
Now I am creating queries with these 3 columns for both tables. I've managed to independently get these results
For example:
SELECT ID, FirstColumn, sum(SecondColumn)
FROM (SELECT ABC||DEF||GHI AS ID, FirstTable.*
FROM FirstTable
WHERE ThirdColumn = *1st condition*)
GROUP BY ID, FirstColumn
;
SELECT ID, SomeColumn, sum(AnotherColumn)
FROM (SELECT JKM||OPQ||RST AS ID, SecondTable.*
FROM SecondTable
WHERE AlsoSomeColumn = *2nd condition*)
GROUP BY ID, SomeColumn
;
So I make a very similar queries for two different tables. I know the results have a certain number of same rows with the ID attribute, the one I've just created in the queries. I need to check which rows in the result are not in the other query's result and vice versa.
Do I have to make temporary tables or views from the queries? Maybe join the two tables in a specific way and only run one query on them?
As a beginner I don't have any experience how to use results as an input for the next query. I'm interested what is the cleanest, most elegant way to do this.
No, you most probably don't need any "temporary" tables. WITH factoring clause would help.
Here's an example:
with
first_query as
(select id, first_column, ...
from (select ABC||DEF||GHI as id, ...)
),
second_query as
(select id, some_column, ...
from (select JKM||OPQ||RST as id, ...)
)
select id from first_query
minus
select id from second_query;
For another result you'd just switch the tables, e.g.
with ... <the same as above>
select id from second_query
minus
select id from first_query
I have an oracle query that uses a created table as part of the code. Every time I need to run a report I delete current data and import the new data I receive. This is one column of id's. I need to create a report on SSRS in which the user can input this data into said table as a parameter. I have designed a simple report that they can enter some of the id's into a parameter, but there may be times when they need to enter in a few thousand id's, and the report already runs long. Here is what the SSRS code currently says:
select distinct n.id, n.notes
from notes n
join (
select max(seq_num) as seqnum, id from notes group by id) maxresults
on n.id = maxresults.ID
where n.seq_num = maxresults.seqnum
and n.id in (#MyParam)
Is there a way to have MyParam insert data into a table I would join called My_ID, joining as Join My_Id id on n.id = id.id
I do not have permissions to create functions or procedures in the database.
Thank you
You may try the trick with MATERIALIZE hint which normally forces Oracle to create a temporary table :
WITH cte1 AS
( SELECT /*+ MATERIALIZE */ 1 as id FROM DUAL
UNION ALL
SELECT 2 DUAL
)
SELECT a.*
FROM table1 a
INNER JOIN cte1 b ON b.id = a.id
I have a list of selected accounts and a table of account records (may or may not be in the selected list) across 40 months. I am able to select all the selected accounts that appear at least once in the table, but I also want to see which accounts appear in all 40 months. Like, I am hoping to do something similar to out join partition by except I want a smaller set of the data.
How can I do that? Thank you!
example:
select distinct table1.acct_no
from table1
inner join selectedAcct
on table1.acct_no = selectedAcct.acct_no
Something lik (not compiled/tested):
with acct_month_list as
(
-- get list of accts/months with missing months
-- as null
select distinct a.acctno, m.monno
from acctrecs a, mons m
where m.monno = a.monno(+)
)
select a2.acctno
from accounts a2
where not exists ( -- any accounst with a null monno have a missing
-- month
select null
from acct_month_list al
where al.acctno = a2.acctno
and a1.monno is null )
and exists ( -- ignore ones that have no records at all
select null
from acctrecs ar
where ar.acctno = a2.acctno )
I have a requirement where in if a PO_ID range is given then I need to do the following:
If a PO_ID from the PO_ID range is present in PS_DISTRIB_LINE then print PO_ID and Voucher ID and if not then print PI_ID and PO_DT from PS_PO_HDR.
How to achieve this.
Union is not working and I am not able to use break logic because if data is present in PS_DISTRIB_LINE then I am printing Sum of PO_AMT Total below the PO_IDs but in other case i am not.
UNION is possible in SQR, but the syntax is difficult.
You will need to put the UNION in parenthesis and make sure to put commas after the selected items. In the example below, I put commas after a.name, a.first_name, and a.last_name. Repeat this for b.name, b.first_name, and b.last_name.
I've run this example and this works for me:
begin-SELECT
employee_name.name
employee_name.first_name
employee_name.last_name
Show 'employee_name.name: ' &employee_name.name
Show 'employee_name.first_name: ' &employee_name.first_name
Show 'employee_name.last_name: ' &employee_name.last_name
from
(
select
a.name,
a.first_name,
a.last_name
from ps_names a
where name_type = 'PRI'
and emplid = '000000001'
union
select
b.name,
b.first_name,
b.last_name
from ps_personal_data b
where emplid = '000000001'
) employee_name
end-SELECT
I have one table, 'a', with id and timestamp. Another table, 'b', has N multiple rows referring to id, and each row has 'type', and "some other data".
I want a LINQ query to produce a single row with id, timestamp, and "some other data" x N. Like this:
1 | 4671 | 46.5 | 56.5
where 46.5 is from one row of 'b', and 56.5 is from another row; both with the same id.
I have a working query in SQLite, but I am new to LINQ. I dont know where to start - I don't think this is a JOIN at all.
SELECT
a.id as id,
a.seconds,
COALESCE(
(SELECT b.some_data FROM
b WHERE
b.id=a.id AND b.type=1), '') AS 'data_one',
COALESCE(
(SELECT b.some_data FROM
b WHERE
b.id=a.id AND b.type=2), '') AS 'data_two'
FROM a first
WHERE first.id=1
GROUP BY first.ID
you didn't mention if you are using Linq to sql or linq to entities. However following query should get u there
(from x in a
join y in b on x.id equals y.id
select new{x.id, x.seconds, y.some_data, y.type}).GroupBy(x=>new{x.id,x.seconds}).
Select(x=>new{
id = x.key.id,
seconds = x.Key.seconds,
data_one = x.Where(z=>z.type == 1).Select(g=>g.some_data).FirstOrDefault(),
data_two = x.Where(z=>z.type == 2).Select(g=>g.some_data).FirstOrDefault()
});
Obviously, you have to prefix your table names with datacontext or Objectcontext depending upon the underlying provider.
What you want to do is similar to pivoting, see Is it possible to Pivot data using LINQ?. The difference here is that you don't really need to aggregate (like a standard pivot), so you'll need to use Max or some similar method that can simulate selecting a single varchar field.