Cannot use comparison operators in ON clause?
[How to reproduce]
ClickHouse server version : v19.11.0
Example with two tables
table1
CREATE TABLE table1
(
str1 String,
num1 UInt64
) ENGINE=MergeTree()
ORDER BY (str1);
table2
CREATE TABLE table2
(
str2 String,
num2 UInt64
) ENGINE=MergeTree()
ORDER BY (str2);
query
SELECT
*
FROM
table1 AS t1
LEFT OUTER JOIN
table2 AS t2
ON
t1.str1 = t2.str2
AND greater(t1.num1, t2.num2) = 1;
error message
DB::Exception: Invalid columns in JOIN ON section. Columns num1 and num2 are from different tables..
Without AND greater(t1.num1, t2.num2) = 1, query is successful.
I think you need ASOF JOIN.
ASOF JOIN is useful when you need to join records that have no exact
match.
For example, SELECT count() FROM table_1 ASOF LEFT JOIN table_2 ON table_1.a == table_2.b AND table_2.t <= table_1.t.
https://clickhouse.com/docs/en/sql-reference/statements/select/join/#asof-join-usage
Related
Title was tough to choose my wording.
I have 2 tables I want to join together via a lg_code. Both columns are VARCHAR2(4 byte). I am running into an issue where table1 lg_code = 0003 and table2 lg_code = 3. The three 0's are causing an issue with the join and not returning all the data needed. How would I go about writing the join clause to fix this issue?
Code:
select * from table1 t1 JOIN table2 t2 ON t1.LG_CODE = t2.LG_CODE
I would suggest to convert the value of the columnlg_code to number first then make the join:
SELECT * FROM table1 t1
JOIN table2 t2 ON to_number(t1.LG_CODE) = to_number(t2.LG_CODE)
you can also use ltrim() on them:
SELECT * FROM table1 t1
JOIN table2 t2 ON LTRIM(t1.LG_CODE, '0') = LTRIM(t2.LG_CODE, '0');
but in newer versions of oracle SQL*PLUS it trims automatically.
I have two tables, Table A has an ID and an Event Date and Table B has an ID, a Description and an Event Date.
Not all IDs in Table A appear in Table B and some IDs appear multiple times in Table B with different Descriptions for each event.
The Description in Table B is an attribute that can change over time, the Event date in Table B is the date that a given ID's Description changes from its default value (kept in another table) to the new value.
I want to find the Description in Table B that matches the Event Date in Table A so, for example
Table Sample Data
A1234 would return Green and A4567 would return Null
I can't create tables here so I need to be able to this with a query.
This query will select last description from before the event:
SELECT * FROM (
SELECT tabA.id, tabA.event_date, tabB.description,
ROW_NUMBER() OVER(PARTITION BY tabB.id ORDER BY tabB.event_date DESC) rn
FROM Table_A tabA
LEFT JOIN Table_B tabB ON tabA.id = tabB.id AND tabB.event_date <= tabA.event_date
) WHERE rn = 1
If I understand well your need, this could be a way:
select a.id, description
from tableA A
left join
(select id,
description,
event_date from_date,
lead(event_date) over (partition by id order by event_date) -1 as to_date
from tableB
) B
on (A.id = B.id and a.event_date between b.from_date and b.to_date)
The idea here is to evaluate, for each row in tableB the range of dates for which that row, and its description, is valid; given this, a simple join should do the job.
You can left join tables like:
select a.ID , b1.DESCRIPTION
from TABLE_A a
left join TABLE_B b1 on a.ID = b1.id and a.EVENT_DATE > b1.EVENT_DATE
left join TABLE_B b2 on a.ID = b2.id and b1.EVENT_DATE < b2.EVENT_DATE and a.EVENT_DATE > b2.EVENT_DATE
where b1.id is null or b2.EVENT_DATE is null;
I want to join two tables together which I have done
I also want to join them based on a condition, where a particular column has a specific value, and I also have done this successfully. I used an inner join and a where clause so far.
However, for this result set, I want to further filter it by selecting ONLY the columns where a particular string appears more than once for a set of columns, eg;
employee_ID and CERTIFICATE
I'd like to group where employee_id has CERTIFICATE count > 2. This is after I have joined the tables together using a where clause.
I am perhaps thinking of using a subquery in my WHERE clause (which is the 3rd line that is also last)
For further clarification, I want to display only employees who have a certificate count greater than 2. By certificate, I am referencing a table with a string 'Certificate' under a column 'Skill'. In other words, select only columns where the string 'Certificate' appears TWICE for a particular employee ID.
To get just the employee ids:
SELECT t1.employee_id
FROM table1 t1
INNER JOIN
table2 t2
ON ( t1.col1 = t2.col1 )
GROUP BY t1.employee_id
HAVING COUNT( CASE t2.skill WHEN 'CERTIFICATE' THEN 1 END ) > 1
Or, to get all the columns:
SELECT *
FROM (
SELECT t1.*,
t2.*,
COUNT( CASE t2.skill WHEN 'CERTIFICATE' THEN 1 END )
OVER ( PARTITION BY t1.employee_id )
AS num_certificate
FROM table1 t1
INNER JOIN
table2 t2
ON ( t1.col1 = t2.col1 )
)
WHERE num_certificate > 1
With our oracle Database/queries that are currently running i have come across some SQL where they have done a table by table join. Now I want to be able to understand this so could someone explain? I am a newbie to this.
SELECT *
FROM ra_customer_trx_all
WHERE customer_trx_id IN
(SELECT customer_trx_id
FROM AR_PAYMENT_SCHEDULES_ALL
WHERE payment_schedule_ID IN
(SELECT payment_schedule_ID
FROM AR_RECEIVABLE_APPLICATIONS_ALL
WHERE applied_customer_trx_id =
SELECT customer_trx_id FROM ra_customer_trx_all WHERE trx_number = '34054'));
1st:
select all TRX records from table ra_customer_trx_all where number = 34054
we are looking for customer_trx_id
select * from ra_customer_trx_all t4 where t4.trx_number = '34054'
2nd: select all records from payment_schedule table that have the IDs from step1
select * from AR_RECEIVABLE_APPLICATIONS_ALL t3 where t3.payment_schedule_ID = (prev select)
3rd: select all records from customer_trx_all table that have the IDs from step2
select * from AR_PAYMENT_SCHEDULES_ALL t2 where t3.customer_trx_id = (prev select)
4th
select * from ra_customer_trx_all t1 where t2.customer_trx_id = (prev select)
5:
summary:
if trx is transation
the logic is:
select all customer transaction records that have been scheduled to be paid via the RECEIVABLE_APPLICATIONS and transaction number is 34054
SELECT t1.*
FROM ra_customer_trx_all t1
inner join AR_PAYMENT_SCHEDULES_ALL t2 on t2.customer_trx_id = t1.customer_trx_id
inner join AR_RECEIVABLE_APPLICATIONS_ALL t3 on t3.payment_schedule_ID = t2.payment_schedule_ID
inner join ra_customer_trx_all t4 on t4.customer_trx_id = t3.applied_customer_trx_id
where t4.trx_number = '34054'
You can replace
select *
from tableA
where columnA in (select columnB
from tableB
where columnB1 in (select ...))
with
select *
from tableA, tableB
where tableA.columnA = tableB.columnB
and tableB.columnB1 in (select ...)
Apply this pattern sequentially to each subquery.
Short explanation: you open outer brackets after IN keyword, move table from inner FROM clause to outer, and add condition to WHERE clause: column before IN have to be equal to column in SELECT clause in subquery.
I have two tables as: table1 with fields c1 and dt(nullable); table2 with fields start_dt, end_dt and wk_id. Now I need to perform left outer join between the table1 and table2 to take wk_id such that dt falls between start_dt and end_dt. I applied following condition but some wk_id which shouldn't be NULL are pulled NULL and some rows get repeated.
where nvl(t1.dt,'x') between nvl(t2.start_dt(+), 'x') and nvl(t2.end_dt(+), 'x');
What is wrong with the condition?
select *
from table1 t1
left join table2 t2
on t1.dt between t2.start_dt and t2.end_dt
I recommend you try the new ANSI join syntax.
Also, are you just using 'x' as an example? Or are the dt columns really stored as strings?
It seems you are missing the part "table1 left outer join table2 on table1.some_field = table2.some_field"
Something like this:
select t1.c1, t1.dt, t2.start_dt, t2.end_dt, t2.wk_id
from table1 t1 left outer join table2 t2
on t1.some_field1 = t2.some_field1
where nvl(t1.dt,'x')
between nvl(t2.start_dt, 'x') and
nvl(t2.end_dt, 'x')