In the following code :
SELECT ... FROM ... CROSS JOIN TABLE ... WHERE ...;
What does CROSS JOIN TABLE mean ?
I searched on the net, but all I can find is about CROSS JOIN only.
I suppose CROSS JOIN TABLE acts on a table, meaning a table like that :
CREATE OR REPLACE ... AS TABLE OF ...;
Here is the full query :
SELECT prog.id_oct_prog_tran_a_participati, prog.code_ressource, prog.instant_depart, prog.commentaire, prog.en_hors_economie_de_comb, discr.delai, discr.valeur_point, MOD(delai, 60) AS H24
FROM req_prog prog
CROSS JOIN TABLE(POINTS_DISCRETS(pIdChronique=>id_chr_substitution)) discr
WHERE horizon <= 'J1'
AND delai > 0
ORDER BY id_oct_prog_tran_a_participati, instant_depart, horizon, delai
POINTS_DISCRETS is a function that returns an element of type TYPE_TAB_POINT. And TYPE_TAB_POINT is a type that the DBA created as following :
create or replace TYPE "TYPE_TAB_POINT" AS TABLE OF TYPE_POINT;
Where TYPE_POINT is a type created as following :
create or replace TYPE "TYPE_POINT" AS OBJECT
(
ID_CHRONIQUE NUMBER,
HORIZON VARCHAR2(2),
NUM_POINT NUMBER(4),
DELAI NUMBER(5),
VALEUR_POINT FLOAT
);
So, as you see here, CROSS JOIN TABLE acts on a table but not a table as we usually mean in a database, more a table like an array.
Is it the case ? And, if yes, how can it be considered like a real table ?
You're parsing the statement incorrectly, which is confusing you I think. CROSS JOIN TABLE isn't one fragment; it's aCROSS JOIN (but could be any join type) between your real table req_prog and, separately, TABLE(...) to tell the query to treat the return value of the function call as a table.
TABLE(...) is the table collection expression:
The table_collection_expression lets you inform Oracle that the value of collection_expression should be treated as a table for purposes of query and DML operations. The collection_expression can be a subquery, a column, a function, or a collection constructor.
Here POINTS_DISCRETS is the collection constructor - returning TYPE_TAB_POINT, which is a collection, most of which you already figured out.
In this case your collection is a table of objects, and treating it as a table allows you both to join and to refer to the attributes of the object that forms each 'row' as if it were a column. The TABLE() is aliased as discr, so you are able to refer to discr.delai - where delai is one of the attributes of the TYPE_POINT type. If you were using an inner or outer join, rather than a cross join, you would use the same construction in the join condition, e.g. ON discr.x = prog.x. Once you apply the table collection expression you just treat it as a table in the rest of the statement.
Related
Can SQLite distinguish between a column from some aliased table, e.g. table1.column and a column that is aliased with the same name, i.e. column, in the SELECT statement?
This is relevant because I need to refer to the column that I construct in the SELECT statement later on in a HAVING clause, but must not confuse it with the column in aliased table. To my knowledge, I cannot alias the table to be constructed in my SELECT statement (without reverting to some nasty work-around like SELECT * FROM (SELECT ...) AS alias) to ensure both are distinguishable.
Here's a stripped down version of the code I am concerned with:
SELECT
a.entity,
b.DATE,
TOTAL(a.dollar_amount*b.ret_usd)/TOTAL(a.dollar_amount) AS ret_usd
FROM holdings a
LEFT JOIN returns b
ON a.stock = b.stock AND
a.DATE = b.DATE
GROUP BY
a.entity,
b.DATE
HAVING
ret_usd NOT NULL
Essentially, I want to get rid of groups for which I cannot find any returns and thus would show up with NULL values. I am not using an INNER JOIN because in my production code I merge multiple types of returns - for some of which I may have no data. I only want to drop those groups for which I have no returns for any of the return types.
To my understanding, the SQLite documentation does not address this issue.
LEFT JOIN all the return tables, then add a WHERE something like
COALESCE(b.ret_used, c.ret_used, d.ret_used....) is not NULL
You might need a similar strategy to determine which ret_used in the TOTAL. FYI, TOTAL never returns NULL.
I'm trying to Replace the schema in existing table using BQ. There are certain fields in BQ which have 3-5 level schema dependency.
For Ex. comsalesorders.comSalesOrdersInfo.storetransactionid this field is nested under two fields.
Since I'm using this to replace existing table, I can not change the field names in query.
The query looks similar to this
SELECT * REPLACE(comsalesorders.comSalesOrdersInfo.storetransactionid AS STRING) FROM CentralizedOrders_streaming.orderStatusUpdated, UNNEST(comsalesorders) AS comsalesorders, UNNEST(comsalesorders.comSalesOrdersInfo) AS comsalesorders.comSalesOrdersInfo
BQ enables unnesting first schema field but presents problem for 2nd nesting.
What changes do I need to make to this query to use UNNEST() for such depedndent schemas ?
Given that you don't have a schema, I will try to provide a generalized answer. Please try to understand the difference between the 2 queries.
-- Provide an alias for each unnest (as if each is a separate table)
select c.stuff
from table
left join unnest(table.first_level_nested) a
left join unnest(a.second_level_nested) b
left join unnest(b.third_level_nested) c
-- b and c won't work here because you are 'double unnesting'
select c.stuff
from table
left join unnest(table.first_level_nested) a
left join unnest(first_level_nested.second_level_nested) b
left join unnest(first_level_nested.second_level_nested.third_level_nested) c
I'm not sure I understand your question, but as I could guess, you want to change one column type to another type, such as STRING.
The UNNEST function is only used with columns that are array types, for example:
"comsalesorders":["comSalesOrdersInfo":{}, comSalesOrdersInfo:{}, comSalesOrdersInfo:{}]
But not with this kind of columns:
"comSalesOrdersInfo":{"storeTransactionID":"X1056-943462","ItemsWarrenty":0,"currencyCountry":"USD"}
Therefore, if a didn't misunderstand your question, I would make a query like this:
SELECT *, CAST(A.comSalesOrdersInfo.storeTransactionID as STRING)
FROM `TABLE`, UNNEST(comsalesorders) as A
SELECT
person.bu_id,
key.key_val,
obj_person_add.person_contact_freq,
obj_person_add.person_contact_best,
OBJ_PERSON_ADD.PERSON_CONTACT_INST,
OBJ_PERSON_ADD.PERSON_CONTACT_DATE,
OBJ_PERSON_ADD.PERSON_BROCHURES,
OBJ_PERSON_ADD.PERSON_NEWSLETTER
FROM obj_person person
INNER JOIN obj_person_add
ON person.obj_id = obj_person_add.obj_id
LEFT JOIN obj_rel_key key
ON key.obj_id = person.obj_id
WHERE person.bu_id in (6,7)
AND person.close_date IS NULL
AND key.obj_key_id = 806
AND (
obj_person_add.person_contact_freq IS NOT NULL
OR obj_person_add.person_contact_best IS NOT NULL
OR OBJ_PERSON_ADD.PERSON_CONTACT_INST IS NOT NULL
OR OBJ_PERSON_ADD.PERSON_CONTACT_DATE IS NOT NULL
OR OBJ_PERSON_ADD.PERSON_BROCHURES IS NOT NULL
OR OBJ_PERSON_ADD.PERSON_NEWSLETTER IS NOT NULL
);
I have built this query, however person_brochures and person_newsletters are stored in a var array. This means that they return (6172,6544...) for example. I want to do a left join to match the ID's in the var array to a name in a different table.
Do I have to loop the var array and somehow match the ID's then?
You might try something called collection unnesting:
SELECT
person.bu_id,
...
OBJ_PERSON_ADD.PERSON_BROCHURES,
OBJ_PERSON_ADD.PERSON_NEWSLETTER
FROM obj_person person
INNER JOIN obj_person_add
ON person.obj_id = obj_person_add.obj_id
...,
TABLE(OBJ_PERSON_ADD.PERSON_BROCHURES) x
INNER JOIN your_other_table
ON x.column_value = your_other_table.id
...
column_value is the name of Oracle pseudocolumn that is assigned to the VARRAY elements.
I am not 100% clear, I am guessing that you are writing this code in C# .Net.
You need to decide where the problem is going to be solved in , are you going to solve it in your App tier or persistence tier ?
I am assuming that you want to solve it in the persistence tier , you have couple of options
1. Generate a prepared statement and execute the statement ..instead of join you will have to rely on IN operator ..etc
Use a stored procedure , pass the two arrays as comma separated string to a stored procedure
you can look at this example if you need to solve it in Oracle function ..so you can do a join as you originally thought.
Splitting string into multiple rows in Oracle
use oracle object relational features and map the data structure appropriately to a structure and use oracle MULTISET like collections to solve the query in a stored procedure ..etc
So we have a db that receives constant input and then we have it moved after x days to a different db as a type of archive/reporting db. So the question is when I try to create a view that combines two of the tables (one from each db):
CREATE VIEW Table_Full AS
SELECT *
FROM [Front].dbo.[DATA] AS A
Inner Join Back.dbo.DATA AS B
ON A.DATETIME=B.DATETIME
I get the following error: "Column names in each view or function must be unique. Column name 'PARTNO' in view or function 'Table_Full' is specified more than once."
So, is there a better way to accomplish what I am trying to do or ?
Given your use case, I think you want a union. That is
select * from table_a
Union all
Select * from table_b
Instead of an asterisk, you have to specify each field and provide aliases for the duplicate field names:
CREATE VIEW Table_Full AS
SELECT
a.ID as A_ID,
b.ID as B_ID,
a.Thingy as A_Thingy,
a.Etcetera as Atcetera
FROM [Front].dbo.[DATA] AS A
Inner Join Back.dbo.DATA AS B
ON A.DATETIME=B.DATETIME
I am trying to join two views I created, however I am joining them using their common field (cAuditNumber).
The issue is, once I have done the joins, it will not let me create the view as it cannot have the field name cAuditNumber twice.
Is the cAuditNumber the PK I should use?
How do I correct this and still join the tables?
CREATE VIEW KFF_Sales_Data_Updated AS
SELECT CustSalesUpdated.*, StkSalesUpdated.*
FROM CustSalesUpdated
INNER JOIN StkSalesUpdated
ON StkSalesUpdated.cAuditNumber = CustSalesUpdated.cAuditNumber
I get the following error:
Msg 4506, Level 16, State 1, Procedure KFF_Sales_Data_Updated, Line 2
Column names in each view or function must be unique. Column name 'cAuditNumber' in view or function 'KFF_Sales_Data_Updated' is specified more than once.
Substitute your own column names instead of ColumnA, Column B, etc, but it should follow this format:
CREATE VIEW KFF_Sales_Data_Updated AS
SELECT CustSalesUpdated.cAuditNumber
,CustSalesUpdated.ColumnA
,CustSalesUpdated.ColumnB
,CustSalesUpdated.ColumnC
,StkSalesUpdated.ColumnA as StkColumnA
,StkSalesUpdated.ColumnB as StkColumnB
,StkSalesUpdated.ColumnC as StkColumnC
FROM CustSalesUpdated
INNER JOIN StkSalesUpdated
ON StkSalesUpdated.cAuditNumber = CustSalesUpdated.cAuditNumber
You only have to alias duplicate columns using "as", or you can use it to rename any column that you so desire.
CREATE VIEW KFF_Sales_Data_Updated AS
SELECT csu.cAuditNumber cAuditNumber1 , ssu.cAuditNumber cAuditNumber2
FROM CustSalesUpdated csu
INNER JOIN StkSalesUpdated ssu
ON StkSalesUpdated.cAuditNumber = CustSalesUpdated.cAuditNumber
You could add any other column in the select statement from the two tables but if there are two column with the same name you should give them aliases
Using select * is a bad practice in general. On the other hand, it is a good practice to alias your table names and columns. Especially in your case, your table names as well as your same columns name(across two tables) could use aliases. The database is confused as to which cAuditNumber is coming from where. So, alias comes in handy.
CREATE VIEW KFF_Sales_Data_Updated
AS
SELECT
csu.cAuditNumber
,csu.Col1
,csu.Col2
,csu.Col3
,ssu.Col1 AS StkCol1
,ssu.Col2 AS StkCol2
,ssu.Col3 AS StkCol3
FROM CustSalesUpdated csu
INNER JOIN StkSalesUpdated ssu ON csu.cAuditNumber = ssu.cAuditNumber