TypeORM subqueries - sql

Based on typeORM docs on using subqueries, there are explained how to create subqueries.
Example:
const qb = await getRepository(Post).createQueryBuilder("post");
const posts = qb
.where("post.title IN " + qb.subQuery().select("user.name").from(User, "user").where("user.registered = :registered").getQuery())
.setParameter("registered", true)
.getMany();
But there is no equivalent as to what the SQL would be.
Supposed that I have the query which contains subqueries like the following:
SELECT a, TO_CHAR (MAX (jointable.f), 'MON YYYY') as f,
t3.c, t3.d, t1.e
FROM table1 t1
LEFT JOIN table2 t2 ON t2.e = t1.e
JOIN table3 t3 ON t3.d = t2.d
JOIN
(SELECT f, t4.g, t5.e, t6.h
FROM table4 t4
JOIN table5 t5 ON t4.g = t5.g
JOIN table6 t6 ON t6.g = t4.g
AND (t6.i = 2
OR (t6.i = 1 AND j = 1)
)
WHERE t4.k = 4
) jointable ON t1.e = jointable.e
WHERE jointable.h = :h
AND(:d = 3 OR
t3."d" = :d
)
GROUP BY a, t3.c, t3.d, t1.e
ORDER BY a ASC
How should I use the typeORM query builder function for the SQL query above?
Assuming that I had created entities related to all table being used on the query above.

I hope this answer could help others to use TypeORM subquery.
const subquery = await getManager()
.createQueryBuilder(table4, 't4')
.select('"t4".f')
.addSelect('"t4".g')
.addSelect('"t5".e')
.addSelect('"t6".h')
.innerJoin(table5, 't5', '"t4".g = "t5".g')
.innerJoin(table6, 't6', '"t6".g = "t4".g')
.where('"t4".k = 4 AND ("t6".i = 2 OR ("t6".i = 1 AND "t6".j = 1))');
model = await getManager()
.createQueryBuilder(table1, 't1')
.select('"t1".a')
.addSelect("TO_CHAR (MAX (jointable.f), 'MON YYYY')", 'f')
.addSelect('"t3".c')
.addSelect('"t3".d')
.addSelect('"t1".e')
.leftJoin('table2', 't2', '"t2".e = "t1".e')
.innerJoin(table3, 't3', '"t3".d = "t2".d')
.innerJoin('('+subquery.getQuery()+')', 'jointable', '"t1".e = jointable.e')
.where('jointable.h = :h AND (:d = 3 OR "t3".d = :d)',
{ h: h, d: d })
.groupBy('"t1".a, "t3".c, "t3".d, "t1".e')
.orderBy('"t1".a', 'ASC')
.getRawMany();
I was using '('+subquery.getQuery()+')' for getting the subquery select query as an equivalent to
(SELECT f, t4.g, t5.e, t6.h ....
......
.... ) jointable ON t1.e = jointable.e
Based on what I understand:
Join actually is equal to inner join
.select is and equivalent of select in SQL. You could also add
aliases (as in SQL).
.addSelect is similar to , in select
There are two types of results you can get using select query
builder: entities or raw results. To describe whether you want
the data as entities (getOne and getMany) or what it
is(getRawOne and getRawMany).

Related

Pl sql get x character of a string in a query

SELECT MR.MUSTERI_ROL_AD AS ACENTE_AD , ////HERE\\\\
(SELECT mrrt.musteri_rol_ad
FROM calisan ct, musteri_rol mrrt, musteri mmt
where ct.bagli_rol_id = a.acente_id
AND ct.calisan_rol_id = mrrt.musteri_rol_id
AND mrrt.musteri_id = mmt.musteri_id
AND ct.teknik_personel='H'
AND ct.calisan_rol_id is not null
and rownum < 2)Bayi_Yetkili_Kisi,
( case when M.TCK_NO is null then M.VKN_NO
else null end)VKN_NO,
(Select (SELECT taa.adresi
FROM tobb_acente ta, tobb_acente_adres taa
WHERE ta.levhano = a.levha_no
AND ta.tobb_acente_sorgu_id = taa.tobb_acente_sorgu_id
AND rownum < 2)
FROM musteri_adres mat, musteri_rol mrt, musteri mt, adres ad
WHERE mrt.musteri_rol_id = a.acente_id
AND mt.musteri_id = mrt.musteri_id
AND mat.musteri_id(+) = mt.musteri_id
AND ad.adres_id(+) = mat.adres_id AND rownum < 2) adress,
(SELECT mi.aciklama
FROM musteri_iletisim mi, musteri_rol_iletisim mri
where mi.musteri_id = m.musteri_id
AND mi.iletisim_tip_kod =
pck_const_iletisim_tip.cep_telefon()
AND mri.musteri_rol_id = mr.musteri_rol_id
and mi.musteri_iletisim_id = mri.musteri_iletisim_id
and rownum < 2) as CEpTELEFON ////// HERE \\\\\
FROM MUSTERI_ROL MR, MUSTERI M, ACENTE A,SATIS_KANALI SK
WHERE MR.MUSTERI_ID = M.MUSTERI_ID
AND MR.MUSTERI_ROL_ID = A.ACENTE_ID
AND A.SATIS_KANALI_ID = SK.SATIS_KANALI_ID
AND MR.ROL_ID = 1
AND A.Uretim_Kaynagi = 'E'
AND A.UST_ACENTE_ID is null
AND MR.Ust_Musteri_Rol_Id is null
AND M.VKN_NO != 'x'
AND TO_CHAR(TRUNC(MR.Bitis_Tarih), 'DD/MM/YYYY') is null or MR.Bitis_Tarih = SYSDATE
Hi guys i need some help about split in Oracle's SQL i get ACENTE_AD x character and i wanna see only first 5 character. and i get CEpTELEFON like 012345678 and i wanna split first 3 character(012) in a column and last 6 character(345678) the in other column. thanks.
You can use substr() string manipulation function to split your phone value in the outer select statement by considering your original query as a subquery.
SELECT t.Bayi_Yetkili_Kisi, t.Vkn_No, t.Adres,
substr(CepTelefonu,1,3) as AlanKodu, substr(CepTelefonu,-6) as CepTelefonu
FROM
(
SELECT MR.MUSTERI_ROL_AD AS ACENTE_AD,
(SELECT mrrt.musteri_rol_ad
FROM musteri_rol mrrt
JOIN calisan ct ON ct.calisan_rol_id = mrrt.musteri_rol_id
JOIN musteri mmt ON mmt.musteri_id = mrrt.musteri_id
WHERE ct.bagli_rol_id = a.acente_id
AND ct.teknik_personel = 'H'
AND ct.calisan_rol_id is not null
AND rownum < 2) as Bayi_Yetkili_Kisi,
(CASE
WHEN M.TCK_NO is null THEN
M.VKN_NO
ELSE
null
END) as Vkn_No,
(SELECT (SELECT taa.adresi
FROM tobb_acente ta
JOIN tobb_acente_adres taa
ON taa.tobb_acente_sorgu_id = ta.tobb_acente_sorgu_id
WHERE ta.levhano = a.levha_no
AND rownum < 2)
FROM musteri mt
JOIN musteri_rol mrt ON mrt.musteri_id = mt.musteri_id
LEFT JOIN musteri_adres mat ON mat.musteri_id = mt.musteri_id
LEFT JOIN adres ad ON ad.adres_id = mat.adres_id
WHERE mrt.musteri_rol_id = a.acente_id
AND rownum < 2) as Adres,
(SELECT mi.aciklama
FROM musteri_iletisim mi
JOIN musteri_rol_iletisim mri ON mri.musteri_iletisim_id = mi.musteri_iletisim_id
WHERE mi.musteri_id = m.musteri_id
AND mi.iletisim_tip_kod = pck_const_iletisim_tip.cep_telefon() -- I think the right hand side implies a stored function, doesn't it?
AND mri.musteri_rol_id = mr.musteri_rol_id
AND rownum < 2) as CepTelefonu
FROM MUSTERI_ROL MR
JOIN MUSTERI M ON M.MUSTERI_ID = MR.MUSTERI_ID
JOIN ACENTE A ON A.ACENTE_ID = MR.MUSTERI_ROL_ID
JOIN SATIS_KANALI SK ON SK.SATIS_KANALI_ID = A.SATIS_KANALI_ID
WHERE MR.ROL_ID = 1
AND A.Uretim_Kaynagi = 'E'
AND A.UST_ACENTE_ID is null
AND MR.Ust_Musteri_Rol_Id is null
AND M.VKN_NO != 'x'
AND to_char(trunc(MR.Bitis_Tarih), 'dd/mm/yyyy') is null
OR MR.Bitis_Tarih = sysdate
) t;
Btw, Consider using ANSI-92 style SQL rather than former ANSI-89 with comma-seperated tables written like the above one. It's easier to write, understand and maintain.

Using a REPLACE function in a SELECT CASE query

I am writing a script where the cable_no is the foreign key to the other tables that I will be joining.
An example of the cable_no may look like this "A01234567B". However, the cable_no in other tables is "A01234567" (basically its the same record without the B at the end)
How do I construct my script such that I remove all the "B" in the cable_no before joining to other tables?
select cc.riser_fid as RISER_FID, cc.cbl_fid as ZH_CBL_FID, f.cable_no AS ZH_CBL_NAME, FM.FACILITY_ID as FACILITY_ID, FC.CHANNEL_ID AS CHANNEL_ID,
ft.FACILITY_TRAIL_ITM_ID AS FACILITY_TRAIL_ITM_ID, ft2.parent_fac_trl_itm_id as parent_fac_trl_itm_id, FT2.TRAIL_SEQ_NO, FT2.A_SITE_ID, ft2.asgn_channel_id,
CASE WHEN
F.CABLE_NO LIKE '%B' REPLACE('B', '')
,CASE
WHEN ft2.a_site_id = a.a_site_id then 1
else null
END EXIST_IN_GTECH
from sgtel10.connected_cables cc
JOIN gc_fcbl_temp f on f.g3e_fid = cc.cbl_fid AND f.ltt_id in (0,888888888)
JOIN FACILITY_MASTER_TEMP FM ON FM.FACILITY_NAME = f.cable_no
JOIN FACILITY_CHANNEL_TEMP FC ON FC.FACILITY_ID = FM.FACILITY_ID AND FC.CHANNEL_ID IS NOT NULL
JOIN FACILITY_TRAIL_ITEMS_TEMP ft on ft.facility_trail_itm_id = fc.facility_trail_itm_id
JOIN FACILITY_TRAIL_ITEMS_TEMP ft2 on ft2.parent_fac_trl_itm_id = ft.parent_fac_trl_itm_id and ft2.trail_seq_no = 1.0
LEFT JOIN A_SITE_ID A ON A.A_SITE_ID = FT2.A_SITE_ID)
;
You can do something like this:
t1 join
t2
on t1.cable_no = t2.cable_no || 'B'
|| is the standard operator for string concatenation.

issue in converting oracle join query to ansi syntax

I am trying to convert the below mentioned query to ansi format
oracle query :
SELECT *
FROM table_1 a,
table_2 b,
table_2 c
WHERE c.dt(+) = a.dt
AND c.ap_no(+) = a.ap_no
AND c.jy_no(+) = a.jy_no
AND c.tn(+) = a.tn
AND b.dt(+) = a.dt
AND b.ap_no(+) = a.ap_no
AND b.jy_no(+) = a.jy_no
AND ( b.t_no(+) + 1 ) = a.t_no --> unable to understand this part
AND ( b.type_cd(+) = 100
AND c.type_cd(+) = 200);
ansi format :
select * from
table2 c right outer join table1 a on
c.dt = a.dt
and c.ap_no = a.ap_no
and c.jy_no = a.jy_no
and c.tn = a.tn
left outer join table2 b on
a.dt = b.dt
and a.ap_no = b.ap_no
and a.jy_no = b.jy_no
and a.t_no = b.t_no ------------------> wrongly implemented it
where b.type_cd = 100 and c.type_cd = 200;
I am not understanding, how to convert the +1 found in the "unable to understand this part" of the Oracle query to the ansi format. Please advise.
Edit : this is not fully similar to the problem explained here . I am just trying to understand the +1 part of the query.

How to Use Case statement in Left outer Join using Operator +?

Query:
select /*+ full(c)parallel(c,4) */ a.*
from ioct_inv_item_all a,
(select udac_group_name, function_order , db_region, workflow_type, change_level
from ioct_function_target
where udac_group_name = 'Banner'
and function_name = 'emptyParam'
and workflow_type = 'CHGFCLTR'
and ('emptyParam' = 'emptyParam' or ('CHGFCLTR' != 'NEWITM' AND change_level = 'emptyParam') or ('CHGFCLTR' = 'NEWITM' and change_level = 'Simple') )
and sysdate between effective_from_date and effective_to_date ) b , item_ca c ,product_ca d,assignment_ca ac ,branches b
where a.udac_group_name = 'Banner'
and a.workflow_type = 'CHGFCLTR'
and a.DB_REGION = b.db_region (+)
and a.workflow_type = b.workflow_type (+)
and a.udac_group_name = b.udac_group_name (+)
and a.change_level = b.change_level (+)
and a.product_code = c.product_code(+)
and a.product_issue_num = c.product_issue_num(+)
and a.item_id = c.item_id(+)
and a.customer_id = c.customer_id(+)
and c.product_code = d.product_code(+)
and c.product_issue_num = d.product_issue_num(+)
and c.product_issue_year = d.product_issue_year(+)
and c.customer_id = d.customer_id(+)
and (case when c.contract_assignment_id IS NOT NULL
AND c.contract_assignment_id > 0
THEN c.contract_assignment_id
ELSE d.regular_assign_id
END) = ac.assignment_id(+)
and ('emptyParam' = 'emptyParam' OR ('CHGFCLTR' = 'NEWITM' AND a.eue_normal_ind = 'emptyParam') OR ('CHGFCLTR' != 'NEWITM' AND a.change_level = 'emptyParam') )
and (('emptyParam') IN ('emptyParam') OR a.region IN ('emptyParam'))
and ('emptyParam' = 'emptyParam'
OR (b.function_order is not null and a.assignee_group_seq = b.function_order)
OR (b.function_order is null and 'emptyParam' = 'emptyParam')
Error:
error:
ORA-01417: a table may be outer joined to at most one other table
01417. 00000 - "a table may be outer joined to at most one other table"
*Cause: a.b (+) = b.b and a.c (+) = c.c is not allowed
*Action: Check that this is really what you want, then join b and c first
in a view.
Error at Line: 28 Column: 20
Does any body suggest any alternative to do same thing without using keyword LEFT OUTER JOIN because i do not want to change the structure of sql query already Written?
The basic idea is that you start with a driving table and then outer join it to other tables. If a is your driving table, then
select x
from a,b,c
where a.x = b.x(+)
and a.y = c.y(+)
is the sort of query oracle expects in the join.
If you really want outer join a table with multiple "driving" tables, you can to use a syntax like this, as pointed out in the error description
Assuming you want to outer join "a" to both "b" and "c"
select *
from a,
(select *
from a,c
where c.y = a.y(+)
)
where b.x = a.x(+)
;

SQL function-like WHERE statement

I've researched for a pretty long time and extensively already on this problem; so far nothing similar has come up. tl;dr below
Here's my problem below.
I'm trying to create a SELECT statement in SQLite with conditional filtering that works somewhat like a function. Sample pseudo-code below:
SELECT col_date, col_hour FROM table1 JOIN table2
ON table1.col_date = table2_col_date AND table1.col_hour = table2.col_hour AND table1.col_name = table2.col_name
WHERE
IF table2.col_name = "a" THEN {filter these records further such that its table2.col_volume >= 600} AND
IF table2.col_name = "b" THEN {filter these records further such that its table2.col_volume >= 550}
BUT {if any of these two statements are not met completely, do not get any of the col_date, col_hour}
*I know SQLite does not support the IF statement but this is just to demonstrate my intention.
Here's what I've been doing so far. According to this article, it is possible to transform CASE clauses into boolean logic, such that you will see here:
SELECT table1.col_date, table1.col_hour FROM table1 INNER JOIN table2
ON table1.col_date = table2.col_date AND table1.col_hour = table2.col_hour AND table1.col_name = table2.col_name
WHERE
((NOT table2.col_name = "a") OR table2.col_volume >= 600) AND
((NOT table2.col_name = "b") OR table2.col_volume >= 550)
In this syntax, the problem is that I still get col_dates and col_hours where at least one col_name's col_volume for that specific col_date and col_hour did not meet its requirement. (e.g. I still get a record entry with col_date = 2010-12-31 and col_hour = 5, but col_name = "a"'s col_volume = 200 while col_name = "b"'s col_volume = 900. This said date and hour should not appear in the query because "a" has a volume which is not >= 600, even if "b" met its volume requirement which is >= 550.)
For tl;dr
If all these are getting confusing, here are sample tables with the sample correct query results so you can just forget everything above and go right on ahead:
table1
col_date,col_hour,col_name,extra1,extra2
2010-12-31,4,"a","hi",1
2010-12-31,4,"a","he",1
2010-12-31,4,"a","ho",1
2010-12-31,5,"a","hi",1
2010-12-31,5,"a","he",1
2010-12-31,5,"a","ho",1
2010-12-31,6,"a","hi",1
2010-12-31,6,"a","he",1
2010-12-31,6,"a","ho",1
2010-12-31,4,"b","hi",1
2010-12-31,4,"b","he",1
2010-12-31,4,"b","ho",1
2010-12-31,5,"b","hi",1
2010-12-31,5,"b","he",1
2010-12-31,5,"b","ho",1
2010-12-31,6,"b","hi",1
2010-12-31,6,"b","he",1
2010-12-31,6,"b","ho",1
table2
col_date,col_hour,col_name,col_volume
2010-12-31,4,"a",750
2010-12-31,4,"b",750
2010-12-31,5,"a",200
2010-12-31,5,"b",900
2010-12-31,6,"a",700
2010-12-31,6,"b",800
The correct query results (with col_volume filters: 600 for 'a' and 550 for 'b') should be:
2010-12-31,4
2010-12-31,6
try this:
SELECT table1.col_date,
table1.col_hour
FROM table1
INNER JOIN table2
ON table1.col_date = table2.col_date
AND table1.col_hour = table2.col_hour
AND table1.col_name = table2.col_name
WHERE EXISTS ( -- here I'm appling the filter logic
select col_date,
col_hour
from table2 sub
where (col_name = 'a' and col_volume >= 600)
or (col_name = 'b' and col_volume >= 550)
and sub.col_date = table2.col_date
and sub.col_hour = table2.col_hour
and sub.col_name = table2.col_name
group by col_date,
col_hour
having count(1) = 2 -- I assume there could be only two rows:
-- one for 'a' and one for 'b'
)
You can check this demo in SQLfiddle
Last thing, you show the same columns from Table1 that you use for the join, but I imagine this is just for the sake of this example
You can try with exists and correlated subquery with case for different conditions in the where clause:
select t1.col_date
, t1.col_hour
from table1 t1
where exists ( select t2.col_volume
from table2 t2
where t2.col_date = t1.col_date
and t2.col_hour = t1.col_hour
and t2.col_name in ('a', 'b')
group by t2.col_volume
having count(t2.col_name >= case when t2.col_name = 'a' then 600 else 550 end) = (select count(*) from table2 where col_name = t2.col_name))
Your boolean transformation is wrong.
Your IFs infer that you are looking for rows that:
table2.col_name = "a" and col_volume >= 600
table2.col_name = "b" and col_volume >= 550
(implicitly) other values for col_name
So, to translate this to SQL:
SELECT table1.col_date, table1.col_hour
FROM table1
INNER JOIN table2 ON table1.col_date = table2.col_date AND
table1.col_hour = table2.col_hour
WHERE (table2.col_name = 'a' AND table2.col_volume >= 600) OR
(table2.col_name = 'b' AND table2.col_volume >= 550) OR
(table2.col_name NOT IN ('a', 'b'))
I think I have an answer (BIG HELP to #mucio's "HAVING" clause; looks like I have to brush up on that).
Apparently the approach was a simple sub-query in which the outer query will do a join on. It's a work-around (not really a direct answer to the problem I posted, I had to reorganize my program flow with this approach), but it got the job done.
Here's the sample code:
SELECT table1.col_date, table1.col_hour
FROM table1
INNER JOIN
(
SELECT col_date, col_hour
FROM table2
WHERE
(col_name = 'a' AND col_volume >= 600) OR
(col_name = 'b' AND col_volume >= 550)
GROUP BY col_date, col_hour
HAVING COUNT(1) = 2
) tb2
ON
table1.col_date = tb2.col_date AND
table1.col_hour = tb2.col_hour
GROUP BY table1.col_date, table1.col_hour