Nested self join, how can I fix it? - sql

SQL can't cast those 2 tables together, does anyone know how to fix it?
select * from
(select ID from tbl_Message
WHERE ([From_User] = '38137F2C-591C-4BE6-91F8-F2C915F26066' OR [To_User] = '38137F2C-591C-4BE6-91F8-F2C915F26066')
AND [Replied_ID] = '00000000-0000-0000-0000-000000000000'
and deleted = 0 ) tbl1 inner join
(select top 1.Replied_ID as Reply_ID, Post_Date as Reply_Date from tbl_Message
where Replied_ID = tbl1.ID or ID = tbl1.ID
order by Post_Date desc) tbl2 on tbl2.Reply_ID =tbl1.ID

I am assuming you are unable to run query as structure is not correct I have updated your query try it.
select * from (
(select ID from tbl_Message
WHERE ([From_User] = '38137F2C-591C-4BE6-91F8-F2C915F26066' OR
[To_User] = '38137F2C- 591C- 4BE6-91F8-F2C915F26066')
AND [Replied_ID] = '00000000-0000-0000-0000-000000000000'
and deleted = 0 ) tbl1
inner join
(select top 1.Replied_ID as Reply_ID, Post_Date as Reply_Date from tbl_Message
where Replied_ID = tbl1.ID or ID = tbl1.ID
order by Post_Date desc) tbl2
on tbl2.Reply_ID =tbl1.ID ) as temp
if everything else you are doing is right it must work.

Related

update multiple columns in oracle

I have query :
UPDATE SDM_KARYAWAN
SET (ID_DIVISI,ID_UNIT_KERJA,ID_JABATAN) =
(
SELECT ID_DIVISI,ID_UNIT_KERJA,ID_JABATAN FROM
(
SELECT TO_CHAR(TGL_SK,'YYYYMMDD') URUT,ID_DIVISI,ID_UNIT_KERJA,ID_JABATAN
FROM SDM_KARYAWAN_JABATAN
WHERE ID_KARYAWAN = '0081005'
ORDER BY URUT DESC
)DETAIL
WHERE ROWNUM = 1
)X
WHERE ID_KARYAWAN = '0081005'
But show error like this : [Err] ORA-00933: SQL command not properly ended
Actually I can use this code :
UPDATE TABLE1 SET COL1 = 'A',COL2='B',COL3='C'...
but What i want is updating multiple columns like this :
UPDATE TABLE1 SET (COL1,COL2,COL3) (SELECT COL1,COL2,COL3 FROM TABLE2)
::EDIT::
I tried this :
SELECT A.ID_DIVISI,A.ID_UNIT_KERJA,A.ID_JABATAN,
DETAIL.ID_DIVISI X,DETAIL.ID_UNIT_KERJA Y,DETAIL.ID_JABATAN Z
FROM SDM_KARYAWAN A
INNER JOIN
(
SELECT ID_KARYAWAN, TO_CHAR(TGL_SK,'YYYYMMDD') URUT,ID_DIVISI,ID_UNIT_KERJA,ID_JABATAN
FROM SDM_KARYAWAN_JABATAN
WHERE ID_KARYAWAN = '0081005'
ORDER BY URUT DESC
)DETAIL
ON DETAIL.ID_KARYAWAN = A.ID_KARYAWAN
WHERE A.ID_KARYAWAN = DETAIL.ID_KARYAWAN
AND ROWNUM = 1
The results :
ID_DIVISI ID_UNIT_KERJA ID_JABATAN X Y Z
-----------------------------------------------------------
D1 D5000 D51000 D2 D200 D2100
Now, i want to update columns on table SDM_KARYAWAN with X,Y,Z value. what's missing from my query? pls.
This will work. Please check.
UPDATE SDM_KARYAWAN
SET (ID_DIVISI,
ID_UNIT_KERJA,
ID_JABATAN) =
(SELECT ID_DIVISI, ID_UNIT_KERJA, ID_JABATAN
FROM ( SELECT TO_CHAR (TGL_SK,'YYYYMMDD')
URUT,
ID_DIVISI,
ID_UNIT_KERJA,
ID_JABATAN
FROM SDM_KARYAWAN_JABATAN
WHERE ID_KARYAWAN = '0081005'
ORDER BY 1 DESC) DETAIL
WHERE ROWNUM = 1)
WHERE ID_KARYAWAN = '0081005'
try this:
UPDATE
(SELECT
Table1.Col1 as OLD1, Table2.Col1 as NEW1
Table1.Col2 as OLD2, Table2.Col2 as NEW2
FROM Table1
INNER JOIN Table2
-- ON Some Join Conditions
) t
SET t.OLD1 = t.NEW1,
SET t.OLD2 = t.NEW2
UPDATE <TABLENAME>
SET STATUS = CASE
WHEN WID = 1 THEN 1
WHEN WID = 2 THEN 0
WHEN WID = 3 THEN 1
END
WHERE WID IN (1,2,3);
NOTE: WHERE COMMAND IS NECESSARY...

Table alias name scope in sub-select query

Please have a look at the query below - I am getting invalid identifier t1.oid in the below inner query.
I have column oid in iclr_request t1
select t1.requestNo
, t2.routeDistance,
, (
select WM_CONCAT(crc7) as "TravCirc7s"
from (
select (
select crc7
from dim_afi_dnld_stn_v1
where stn_sys_nbr = t3.stn_sys_nbr
and rownum=1
) as crc7
from iclr_trav_circ7 t3
where request_oid = **t1.oid**
and sub_route_index=0
and station_type_oid = 1
order by sequence
)
)
from iclr_request t1
, iclr_summary_results t2
where t1.oid = t2.request_oid
You can try this:
select t1.requestNo , t2.routeDistance,
WM_CONCAT((select crc7 from dim_afi_dnld_stn_v1 where stn_sys_nbr = t3.stn_sys_nbr and rownum=1)) as "TravCirc7s"
from iclr_request t1
join iclr_summary_results t2 on t1.oid = t2.request_oid
left join iclr_trav_circ7 t3 on t3.request_oid = t1.oid
and t3.sub_route_index=0
and t3.station_type_oid = 1
group by t1.requestNo , t2.routeDistance;
Correlated subqueries may refer their parents only 1 level above (although some Oracle documentation says it's unlimited)
EDIT: It doesn't save the order by sequence in WM_CONCAT. You may need to wrap it a parent query and then wm_concat

Is there a way to make this query more efficient performance wise?

This query takes a long time to run on MS Sql 2008 DB with 70GB of data.
If i run the 2 where clauses seperately it takes a lot less time.
EDIT - I need to change the 'select *' to 'delete' afterwards, please keep it in mind when answering. thanks :)
select *
From computers
Where Name in
(
select T2.Name
from
(
select Name
from computers
group by Name
having COUNT(*) > 1
) T3
join computers T2 on T3.Name = T2.Name
left join policyassociations PA on T2.PK = PA.EntityId
where (T2.EncryptionStatus = 0 or T2.EncryptionStatus is NULL) and
(PA.EntityType <> 1 or PA.EntityType is NULL)
)
OR
ClientId in
(
select substring(ClientID,11,100)
from computers
)
Swapping IN for EXISTS will help.
Also, as per Gordon's answer: UNION can out-perform OR.
SELECT computers.*
FROM computers
LEFT
JOIN policyassociations
ON policyassociations.entityid = computers.pk
WHERE (
computers.encryptionstatus = 0
OR computers.encryptionstatus IS NULL
)
AND (
policyassociations.entitytype <> 1
OR policyassociations.entitytype IS NULL
)
AND EXISTS (
SELECT name
FROM (
SELECT name
FROM computers
GROUP
BY name
HAVING Count(*) > 1
) As duplicate_computers
WHERE name = computers.name
)
UNION
SELECT *
FROM computers As c
WHERE EXISTS (
SELECT SubString(clientid, 11, 100)
FROM computers
WHERE SubString(clientid, 11, 100) = c.clientid
)
You've now updated your question asking to make this a delete.
Well the good news is that instead of the "OR" you just make two DELETE statements:
DELETE
FROM computers
LEFT
JOIN policyassociations
ON policyassociations.entityid = computers.pk
WHERE (
computers.encryptionstatus = 0
OR computers.encryptionstatus IS NULL
)
AND (
policyassociations.entitytype <> 1
OR policyassociations.entitytype IS NULL
)
AND EXISTS (
SELECT name
FROM (
SELECT name
FROM computers
GROUP
BY name
HAVING Count(*) > 1
) As duplicate_computers
WHERE name = computers.name
)
;
DELETE
FROM computers As c
WHERE EXISTS (
SELECT SubString(clientid, 11, 100)
FROM computers
WHERE SubString(clientid, 11, 100) = c.clientid
)
;
Some things I would look at are
1. are indexes in place?
2. 'IN' will slow your query, try replacing it with joins,
3. you should use column name, I guess 'Name' in this case, while using count(*),
4. try selecting required data only, by selecting particular columns.
Hope this helps!
or can be poorly optimized sometimes. In this case, you can just split the query into two subqueries, and combine them using union:
select *
From computers
Where Name in
(
select T2.Name
from
(
select Name
from computers
group by Name
having COUNT(*) > 1
) T3
join computers T2 on T3.Name = T2.Name
left join policyassociations PA on T2.PK = PA.EntityId
where (T2.EncryptionStatus = 0 or T2.EncryptionStatus is NULL) and
(PA.EntityType <> 1 or PA.EntityType is NULL)
)
UNION
select *
From computers
WHERE ClientId in
(
select substring(ClientID,11,100)
from computers
);
You might also be able to improve performance by replacing the subqueries with explicit joins. However, this seems like the shortest route to better performance.
EDIT:
I think the version with join's is:
select c.*
From computers c left outer join
(select c.Name
from (select c.*, count(*) over (partition by Name) as cnt
from computers c
) c left join
policyassociations PA
on T2.PK = PA.EntityId and PA.EntityType <> 1
where (c.EncryptionStatus = 0 or c.EncryptionStatus is NULL) and
c.cnt > 1
) cpa
on c.Name = cpa.Name left outer join
(select substring(ClientID, 11, 100) as name
from computers
) csub
on c.Name = csub.name
Where cpa.Name is not null or csub.Name is not null;

I have a table where i need to select the max value of one column

Ive found a couple solutions one in particular that was of great help, and nearly got me there, but im stuck on the last bit. All i need to do now is be able to specify a range for the CarNumbers to be displayed.
the SQL might make more sense...
SELECT sr.* FROM StatusReport sr
INNER JOIN ( SELECT CarNumber, MAX(StatusReportTime) AS MaxDateTime
FROM StatusReport GROUP BY CarNumber ) groupedsr ON sr.CarNumber =
groupedsr.CarNumber AND sr.StatusReportTime = groupedsr.MaxDateTime
I basically want to be able to add the following line in.
WHERE CarNumber BETWEEN '0' AND '3999'
Could anyone help me out?
Thanks in advance,
Mike
You can add it at the end of the outer query, or at the end of the subquery before the GROUP BY clause like so:
SELECT sr.*
FROM StatusReport sr
INNER JOIN
(
SELECT CarNumber, MAX(StatusReportTime) AS MaxDateTime
FROM StatusReport
WHERE CarNumber BETWEEN '0' AND '3999'
GROUP BY CarNumber
) groupedsr ON sr.CarNumber = groupedsr.CarNumber
AND sr.StatusReportTime = groupedsr.MaxDateTime;
SELECT sr.*
FROM StatusReport sr
INNER JOIN
(SELECT CarNumber,
MAX(StatusReportTime) AS MaxDateTime
FROM StatusReport
WHERE CarNumber >0
GROUP BY CarNumber) groupedsr ON sr.CarNumber = groupedsr.CarNumber
AND sr.StatusReportTime = groupedsr.MaxDateTime
you can do it like this.. this will be easy to understand and will simplify your query
with tbl2 as
(
select tbl1.*,
row_number() over (order by CarNumber) rtn
from
(select CarNumber, max(StatusReportTime) as MaxDateTime from [StatusReport] group by
CarNumber) as tbl1
)
select * from tbl2 where rtn between 0 and 3999

MySQL/SQL - When are the results of a sub-query avaliable?

Suppose I have this query
SELECT * FROM (
SELECT * FROM table_a
WHERE id > 10 )
AS a_results LEFT JOIN
(SELECT * from table_b
WHERE id IN
(SElECT id FROM a_results)
ON (a_results.id = b_results.id)
I would get the error "a_results is not a table". Anywhere I could use the re-use the results of the subquery?
Edit: It has been noted that this query doesn't make sense...it doesn't, yes. This is just to illustrate the question which I am asking; the 'real' query actually looks something like this:
SELECT SQL_CALC_FOUND_ROWS * FROM
( SELECT wp_pod_tbl_hotel . *
FROM wp_pod_tbl_hotel, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =12
AND wp_pod_rel.tbl_row_id =1
AND wp_pod.tbl_row_id = wp_pod_tbl_hotel.id
AND wp_pod_rel.pod_id = wp_pod.id
) as
found_hotel LEFT JOIN (
SELECT COUNT(*) as review_count, avg( (
location_rating + staff_performance_rating + condition_rating + room_comfort_rating + food_rating + value_rating
) /6 ) AS average_score, hotelid
FROM (
SELECT r. * , wp_pod_rel.tbl_row_id AS hotelid
FROM wp_pod_tbl_review r, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =11
AND wp_pod_rel.pod_id = wp_pod.id
AND r.id = wp_pod.tbl_row_id
AND wp_pod_rel.tbl_row_id
IN (
SELECT wp_pod_tbl_hotel .id
FROM wp_pod_tbl_hotel, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =12
AND wp_pod_rel.tbl_row_id =1
AND wp_pod.tbl_row_id = wp_pod_tbl_hotel.id
AND wp_pod_rel.pod_id = wp_pod.id
)
) AS hotel_reviews
GROUP BY hotel_reviews.hotelid
ORDER BY average_score DESC
AS sorted_hotel ON (id = sorted_hotel.hotelid)
As you can see, the sub-query which makes up the found_query table is repeated elsewhere downward as another sub-query, so I was hoping to re-use the results
You can not use a sub-query like this.
I'm not sure I understand your query, but wouldn't that be sufficient?
SELECT * FROM table_a a
LEFT JOIN table_b b ON ( b.id = a.id )
WHERE a.id > 10
It would return all rows from table_a where id > 10 and LEFT JOIN rows from table_b where id matches.