Oracle Database Link + Inner Join + To_Number Query - oracle
DatabaseA - TableA - FieldA VARCHAR2
DatabaseB - TableB - FieldB NUMBER [dblink created]
SELECT *
FROM TableB#dblink b
INNER JOIN TableA a
ON b.FieldB = a.FieldA
There are 2 complications.
1. FieldA is VARCHAR2 but FieldB is NUMBER.
2. FieldA contains - and FieldB contains 0.
More info about the fields
FieldA: VARCHAR2(15), NOT NULL
Sample values
-
123
No non-numeric values, except for -
FieldB: NUMBER(5,0)
Sample values
0
123
No non-numeric values
What I'm trying to do is to ignore the rows if FieldA='-' OR FieldB=0, otherwise compare FieldA to FieldB.
SELECT *
FROM TableB#dblink b
JOIN TableA a
ON to_char(b.FieldB) = a.FieldA
I get the following error:
SQL Error: 17410, SQLState: 08000
No more data to read from socket.
NULLs will never match with equals, so your join already takes care of that.
You would get an implicit type conversion of (probably) the NUMBER to VARCHAR, so that should also be taken care of.
Having said that, I am a big proponent of not relying on implicit datatype conversions. So I would write my query as
SELECT *
FROM TableB#dblink b
JOIN TableA a
ON to_char(b.FieldB) = a.FieldA
If that is not giving the results you want, perhaps posting examples of the data in each table and the results you desire would be helpful.
Related
I tested in my SQL Developer one case about "Subquery in Order By"
I have question about "Subquery in Order by clause". The below request returns the error. Is it means that Subquery in Order by clause must be scalar? select * from employees order by (select * from employees where first_name ='Steven' and last_name='King'); Error: ORA-00913: too many values 00913. 00000 - "too many values"
Yes, it means that if you use a subquery in ORDER BY it must be scalar. With select * your subquery returns multiple columns and the DBMS would not know which of these to use for the sorting. And if you selected one column only, you would still have to make sure you only select one row of course. (The difference is that Oracle sees the too-many-columns problem immediately, but detect too many rows only when fetching the data.) This would be allowed: select * from employees order by (select birthdate from employees where employee_id = 12345); This is a scalar query, because it returns only one value (one column, one row). But of course this still makes as little sense as your original query, because the subquery result is independent from the main query, i.e. it returns the same value for every row in the table and thus no sorting takes effect. A last remark: A subquery in ORDER BY makes very seldomly sense, because that would mean you order by something you don't display. The exception is when looking up a sortkey. E.g.: select * from products p where type = 'shirt' and color = 'blue' and size in ('S', 'M', 'L', 'XL') order by (select sortkey from sizes s where s.size = p.size);
It means that valid options for ORDER BY clause can be expression, position or column alias A subquery is neither of these.
Trying to display top 3 amount from a table using sql query in oracle 11g..column is of varchar type
Am trying to list top 3 records from atable based on some amount stored in a column FTE_TMUSD which is of varchar datatype below is the query i tried SELECT *FROM ( SELECT * FROM FSE_TM_ENTRY ORDER BY FTE_TMUSD desc ) WHERE rownum <= 3 ORDER BY FTE_TMUSD DESC ; o/p i got 972,9680,963 -->FTE_TMUSD values which are not displayed in desc I am expecting an o/p which will display the top 3 records of values
That should work; inline view is ordered by FTE_TMUSD in descending order, and you're selecting values from it. What looks suspicious are values you specified as the result. It appears that FTE_TMUSD's datatype is VARCHAR2 (ah, yes - it is, you said so). It means that values are sorted as strings, not numbers - and it seems that you expect numbers. So, apply TO_NUMBER to that column. Note that it'll fail if column contains anything but numbers (for example, if there's a value 972C). Also, an alternative to your query might be use of analytic functions, such as row_number: with temp as (select f.*, row_number() over (order by to_number(f.fte_tmusd) desc) rn from fse_tm_entry f ) select * from temp where rn <= 3;
SQL Tuning for IN Clause
The below Teradata query is taking around 18 seconds to complete. The highlighted values passed in IN clause is from another Oracle database so I am not able to implement a join with that table. SELECT distinct sec.SerialNum esn, ef.EngineFamilyCd family, em.EngineModelCd model, es.EngineSeriesCd series, sac.AircraftTailNum tailNumRef, sec.EnginePositionNum enginePosition, o1.OrganizationId ownerOrgId, o2.OrganizationId operatorOrgId, sec.EngineInstallationDttm installedDate, sec.EngineRemovalDttm removalDate, sec.HardwareConfigNm hardwareConfig, sec.EngineControlNm engineControl, sec.ApplicationSelectorNm appSelector, sec.EngineMonitorInd engineMonitorInd, sec.EngineThrustRatingFctr engineThrustRating, sec.StatusDesc engineStatus, sec.n1modifiernum n1modifier FROM DB_MASTER_BV.SZEngineCurrent sec, DB_MASTER_BV.EngineSeries es, DB_MASTER_BV.EngineModel em, DB_Master_BV.EngineFamily ef, DB_MASTER_BV.SZAircraftCurrent sac, DB_MASTER_BV.Organization o1, DB_MASTER_BV.Organization o2 WHERE sec.EngineSeriesCd = es.EngineSeriesCd and es.EngineModelCd = em.EngineModelCd and em.EngineFamilyCd = ef.EngineFamilyCd and sec.MasterAircraftId = sac.MasterAircraftId and o1.MasterOrganizationId = sec.OwnerMasterOrganizationId and o2.MasterOrganizationId = sec.OperatorMasterOrganizationId AND (sec.SerialNum in('733276','193283','690168','741471','876374','873383','193386','906397','804314','900116','785670','900399','724321','193488','811373','779917','193699','994688', '779410','575169','A59299','900206','193297','575484','896359','367230','810105','876485','906385','876484','707149','811222','706801','193596','731949','697881', '889697','804626','575194','707159','706129','900230','900231','706834','811352','900229','785748','193460','888221','906272','906266','906264','906263','994356', '194431','731966','892417','811341','577413','741572','575564','889262','706956','876157','900257','900153','706958','706957','960436','892429','892427','900354', '697138','645655','193352','994337','707189','697833','959190','900246','811317','577437','193643','697976','890692','193229','965579','900137','900135','894897', '697723','193363','193367','785505','907077','959184','811311','706526','577302','706529','994332','702792','706663','779834','731931','960127','193371','876183', '741563','193235','803843','577320','994318','907087','741460','907086','959170','994462','900464','193626','877503','643711','811202','811201','704585','193504', '193500','875246','704876','725834','699783','699780','802380','900304','706885','906191','577773','959152','872574','811435','697388','699381','892485','577698', '907035','811445','907039','894999','894857','894595','697273','894597','959139','577894','874898','706959','900424','193337','577697','907011','875696','699555', '699554','575629','906149','906150','193452','962968','811264','811266','962970','875395','699543','575638','906153','857962','896247','858349','779746','906161', '906928','802857','779640','193424','550309','424520','550305','575608','872517','906169','892196','811386','811385','906173','907220','959234','876666','959231', '876662','893785','875914','802649','550218','550315','906111','741984','550319','906405','906501','550118','643371','785254','550116','550117','802946','906629', '907145','550325','550324','906837','550320','906838','702591','550220','550227','906415','690289','906517','704416','731431','550125','959201','906413','994176', '550333','550140','550337','891651','550141','550338','906746','907269','550132','550137','550138','892914','550342','906123','550153','550345','950923','906129', '873188','906850','906953','690270','890713','645352','893127','697590','874826','424439','893126','907110','550144','856305','690269','892824','550256','550257', '906867','907186','960852','720754','960851','906866','888607','805573','811530','960756','872352','550266','550267','550264','811518','888896','906730','994958', '892247','960970','875186','906987','424124','550232','A59303','702660','875885','811609','888626','424219','906897','994981','731502','697496','695345','962996', '894371','907153','805541','907154','424337','906613','906615','900512','906610','956141','994611','804582','994718','888648','575219','888756','896973','424395', '872117','A59227','697616','731380','697614','900161','690410','994213','956155','956154','779492','994231','702876','577248','994727','193818','890879','722243', '906499','577354','888560','645121','896972','960823','804279','900175','888853','193724','550285','550282','906469','994803','906466','888299','877141','890984', '695688','994533','888327','A59348','A59346','994410','733116','550296','550290','550292','906478','731763','725658','896408','645145','994751','731654','740358', '906441','550158','193849','906543','906448','994262','575824','424186','906345','643663','888305','906243','906244','702963','906453','906452','956119','906451', '956116','950489','550166','906454','367457','896764','575833','994268','906252','994127','733236','906258','956123','550178','994777','956126','956127','956128', '906786','906788','906687','643290','994631','956225','994632','888574','906365','804228','731599','643682','550182','804369','994784','550186','550183','888826', '575127','906439','890482','906438','906691','890472','994509','193147','575718','804215','575276','994793','897257')) and END(sec.EngineValidPd) is until_changed order by esn Also if there is more than 1000 records, I am implementing the IN clause as follows AND (sec.SerialNum in( first 999 recods) OR sec.SerialNum in( next 999 recods)… OR sec.SerialNum in( remaining recods)) Please suggest solution which would be faster than the above query and which will not cause issue with more than 1000 records in IN clause
What is your Teradata release? In TD14 there's a built-in table function to split a string of values, you can simply pass all values within a single string: AND sec.SerialNum IN ( SELECT token FROM TABLE (STRTOK_SPLIT_TO_TABLE(1, '733276,193283,690168,741471,876374', ',') RETURNS (outkey INTEGER, tokennum INTEGER, token VARCHAR(20) CHARACTER SET UNICODE) ) AS d )
pl-sql include column names in query
A weird request maybe but. My boss wants me to create an admin version of a page we have that displays data from an oracle query in a table. The admin page, instead of displaying the data (query returns 1 row), needs to return the table name and column name Ex: Instead of: Name Initial ================== Bob A I want: Name Initial ============================ Users.FirstName Users.MiddleInitial I realize I can do this in code but would rather just modify the query to return the data I want so I can leave the report generation code mostly alone. I don't want to do it in a stored procedure. So when I spit out the data in the report using something like: blah blah = MyDataRow("FirstName") I can leave that as is but instead of it displaying "BOB" it would display "Users.FirstName" And I want to do the query using select * if possible instead of listing all the columns So for each of the columns I am querying in the * , I want to get (instead of the column value) the tablename.ColumnName or tablename|columnName hope you are following- I am confusing myself... pseudo: select tablename + '.' + Columnname as WhateverTheColumnNameIs from Table1 left join Table2 on whatever... Join Table_Names on blah blah Whew- after writing all this I think I will just do it on the code side. But if you are up for it maybe a fun challenge
Oracle does not provide an authentic way(there is no pseudocolumn) to get the column name of a table as a result of a query against that table. But you might consider these two approaches: Extract column name from an xmltype, formed by passing cursor expression(your query) in the xmltable() function: -- your table with t1(first_name, middle_name) as( select 1,2 from dual ), -- your query t2 as( select * -- col1 as "t1.col1" --, col2 as "t1.col2" --, col3 as "t1.col3" from hr.t1 ) select * from ( select q.object_value.getrootelement() as col_name , rownum as rn from xmltable('//*' passing xmltype(cursor(select * from t2 where rownum = 1)) ) q where q.object_value.getrootelement() not in ('ROWSET', 'ROW') ) pivot( max(col_name) for rn in (1 as "name", 2 as "initial") ) Result: name initial --------------- --------------- FIRST_NAME MIDDLE_NAME Note: In order for column names to be prefixed with table name, you need to list them explicitly in the select list of a query and supply an alias, manually. PL/SQL approach. Starting from Oracle 11g you could use dbms_sql() package and describe_columns() procedure specifically to get the name of columns in the cursor(your select).
This might be what you are looking for, try selecting from system views USER_TAB_COLS or ALL_TAB_COLS.
Expected CHAR got NUMBER
DB: Oracle 11g Query: SELECT CASE WHEN rs.OPTION = '3' THEN (SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0 FROM CRSIDM.SUB_OPTS ex INNER JOIN CRSIDM.SUB_OPTS_GRP cg ON cg.GROUP_ID = ex.GRP_ID ) ELSE (SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0 FROM CRSIDM.SUB_OPTS ex INNER JOIN CRSIDM.SUB_OPTS_POL cg ON cg.GROUP_ID = ex.GRP_ID ) END AS PROPTS FROM PR_OPTS I am getting error 'expected CHAR got NUMBER', here EXTS,GROUP_ID & GRP_ID are numeric. Then how there is a chance of expecting CHAR?
Generally when Oracle compares different datatypes such as a NUMBER with a CHARACTER, implicit conversion kicks in and all is well (provided the data can be converted.) For example, if you have a function that expects a CHARACTER value but you pass it a NUMBER, all is well - Oracle simply converts the NUMBER to character. E.g. a function like this: create or replace function get_something(p_id VARCHAR2) return number ... works if you call it with this: get_dno(10); or this: get_dno('10'); and in SQL: select * from some_table where numeric_column = '10' -- no problem. A popular place where you see this kind of error is with the return values in CASE statements. For instance, you'll get that error if you have something like this: SQL> SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END 2 FROM dual 3 ; SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END * ERROR at line 1: ORA-00932: inconsistent datatypes: expected CHAR got NUMBER (The datatype from the first WHEN clause is what it expects in the other WHEN/ELSE clauses that follow.) But in your case the WHEN and THEN both return counts - the datatypes are consistent. So, I think you have a red-herring in there. As Alex mentioned above, OPTION is a keyword and if you try and create a table with that as a column name, Oracle disagrees: SQL> create table dummy 2 (option varchar2(10) 3 ); (option varchar2(10) * ERROR at line 2: ORA-00904: : invalid identifier This works: SQL> create table dummy 2 (option_col varchar2(10) 3 ); Table created. or you could do it with quotes: SQL> create table dummy 2 ("option" varchar2(10)); Table created. But now you're in a world of hurt - you need quotes from now on: SQL> select option from dummy; select option from dummy * ERROR at line 1: ORA-00936: missing expression SQL> select d.option from dummy d; select d.option from dummy d * ERROR at line 1: ORA-01747: invalid user.table.column, table.column, or column specification With quotes: SQL> select d."option" from dummy d; no rows selected So, if your query is really giving you "expected CHAR, got NUMBER", it looks to me like something is off.
Essentially, it means some of the fields you are using aren't compatible with each other. It's basically a "type mismatch". Just check to see if any types of CHAR are being used with types of NUMBER. Then you can either switch the type of one, or simply use a conversion as part of the query.
The issue is OPTION = '3', the quotation marks indicate that you're looking for a string containing the solitary character 3. Try this instead: SELECT CASE WHEN rs.OPTION = 3 THEN (SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0 FROM CRSIDM.SUB_OPTS ex INNER JOIN CRSIDM.SUB_OPTS_GRP cg ON cg.GROUP_ID = ex.GRP_ID) ELSE (SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0 FROM CRSIDM.SUB_OPTS ex INNER JOIN CRSIDM.SUB_OPTS_POL cg ON cg.GROUP_ID = ex.GRP_ID) END AS PROPTS FROM PR_OPTS