Delete with subquery that produces two columns (in Postgresql) - sql

I have to delete a few records that match two columns calculated with a subquery.
I can properly see them with this query:
select * from user_assignments as ua,
(
select user_assignments.user_id as uid,
job_selection as jid
from user_assignments
join job_selections on job_id = jobs.id
join data on job_selections.data_id = data.id
where data.my_column IS NULL
) as sq
where sq.uid = ua.user_id AND ua.job_selection_id = sq.jid;
This works, and I see the 7 assignments I want to delete.
However, deleting is not as easy as changing the SELECT by DELETE...
If I do:
delete from user_assignments as ua,
(
...
) as sq
where sq.uid = ua.user_id AND sq.jid = ua.job_selection_id;
I get:
ERROR: syntax error at or near ","
I've tried quite an assortment of combinations, yet I can't get it to work. I imagine it must be quite simple, but I'm quite a newbie in SQL.
Basically, I have a subquery that properly produces two columns that I can use for a SELECT FROM user_assignments and now I want to DELETE FROM user_assignments the records that I know I can SELECT.
Any hints would be very appreciated. Thank you in advance.

Use in or exists:
delete from user_assignments ua
where exists (select 1
from user_assignments ua2 join
job_selections js
on ua2.job_id = js.id join
data d
on js.data_id = d.id
where d.my_column IS NULL and
ua.user_id = sq.uid and ua.job_selection_id = sq.jid
);

Oh, I got it (I think).
Kuddos to this tutorial this tutorial and particularly, the section SQL delete records using subqueries with alias.
If someone else is interested, what I did was:
DELETE FROM user_assignments ua
WHERE EXISTS(
SELECT user_assignments.user_id as uid,
user_assignments.job_selection as jid
FROM user_assignments
join job_selections on job_id = jobs.id
join data on job_selections.data_id = data.id
WHERE data.my_column IS NULL
AND ua.user_id = uid
AND ua.job_selection = jid
)
This query also works fine with SELECT * FROM user_assignments

Related

postgres: LEFT JOIN table and field does not exist

This is my query
SELECT org.id,
org.name,
org.type,
org.company_logo,
(SELECT org_profile.logo_url FROM org_profile WHERE org_profile.org_id = org.id AND org_profile.status = 'active' ORDER BY org_profile.id DESC LIMIT 1) as logo_url,
org.short_description,
org_profile.value_prop,
count(*) OVER () AS total
FROM org
LEFT JOIN user_info ON user_info.id = org.approved_by
INNER JOIN (select distinct org_profile.org_id from org_profile) org_profile ON org_profile.org_id = org.id
WHERE
org.type = 'Fintech'
AND org.status = 'APPROVED'
AND org.draft != TRUE
ORDER BY org.id DESC
I am using LEFT JOIN query with my org_profile table. I used distinct for unique org id but the problem is org_profile.value_prop column does not work. The error is showing column org_profile.value_prop does not exist
I'm trying to solve this issue. But I don't figure out this issue.
basically, the error informs that you try to get the value_prop field from org_profile subquery, which basically doesn't exist.
It's difficult to give a working query by writting just on the paper, but I think that:
it's worth to apply the handy aliasses for each subquery
deduplication, if required, should be done in the subquery. When multiple fields used DISTINCT may be insufficient - RANK function may be required.
you make some operations to get the logo_url by a scalar subquery - it seems a bit strange, especially the same table is used in JOIN - I would suggest to move all logic related to org_profile to the subquery. Scalar expressions would throw an error in case multiple values would be found in output.
SELECT
org.id,
org.name,
org.type,
org.company_logo,
prof.logo_url,
org.short_description,
prof.value_prop,
count(*) OVER () AS total
FROM org
JOIN (
select distinct org_id, logo_url, value_prop -- other deduplication type (RANK) may be required
from org_profile
where status = 'active' -- ?
) prof ON org.id = prof.org_id
LEFT JOIN user_info usr ON usr.id = org.approved_by
WHERE
org.type = 'Fintech'
AND org.status = 'APPROVED'
AND org.draft != TRUE
ORDER BY org.id DESC

SQL UPDATE statement with LEFT JOIN, GROUP BY and HAVING?

I need to update some rows in a table. I've created a Select statement to make sure I've got the rows I wanted to select.
I want to update task_status_id in the table task, and I've tried in various ways but always end up with a syntax error and have honestly no idea how to do so even though I've tried to follow others examples by using INNER JOIN and putting the select statement in parenthesis. Any help would be appreciated.
UPDATE statement to merge with the SELECT statement.
UPDATE task
SET task_status_id = (SELECT task_status_id
FROM task_status
WHERE task_type_id = 1
AND name = 'Completed');
WHERE
SELECT
t.task_id
FROM task t
LEFT JOIN user u
ON t.user_id = u.user_id
LEFT JOIN contract co
ON u.user_id = co.user_id
LEFT JOIN task_status ts
ON t.task_status_id = ts.task_status_id
WHERE co.status = 'Closed' AND
t.task_type_id = 1 AND
t.task_status_id != (SELECT task_status_id
FROM task_status
WHERE task_type_id = 1
AND name = 'Completed')
GROUP BY t.task_id
HAVING count(t.contract_id) <= 2;
First of all, it doesn't make sense to use LEFT JOIN contract co and then filter results using co.status = 'Closed', because if you're going to filter by a column from a joined table then you should use INNER JOIN (unless you're comparing to null in the filter).
Secondly, syntax here is incorrect - you should use not in instead of !=
AND t.task_status_id != (SELECT task_status_id
FROM task_status
WHERE task_type_id = 1
AND name = 'Completed')
However, since you already joined the task_status table you can replace the above block of code with the following (assuming that task_status_id is a unique column):
AND ts.name != 'Completed'
Either way, you should post sample data and expected result.

How do I fix the syntax of a sub query with joins?

I have the following query:
SELECT tours_atp.NAME_T, today_atp.TOUR, today_atp.ID1, odds_atp.K1, today_atp.ID2, odds_atp.K2
FROM (players_atp INNER JOIN (players_atp AS players_atp_1 INNER JOIN (today_atp INNER JOIN odds_atp ON (today_atp.TOUR = odds_atp.ID_T_O) AND (today_atp.ID1 = odds_atp.ID1_O) AND (today_atp.ID2 = odds_atp.ID2_O) AND (today_atp.ROUND = odds_atp.ID_R_O)) ON players_atp_1.ID_P = today_atp.ID2) ON players_atp.ID_P = today_atp.ID1) INNER JOIN tours_atp ON today_atp.TOUR = tours_atp.ID_T
WHERE (((tours_atp.RANK_T) Between 1 And 4) AND ((today_atp.RESULT)="") AND ((players_atp.NAME_P) Not Like "*/*") AND ((players_atp_1.NAME_P) Not Like "*/*") AND ((odds_atp.ID_B_O)=2))
ORDER BY tours_atp.NAME_T;
I'd like to add a field to this query that provides me with the sum of a field in another table (FS) with a few criteria applied.
I've been able to build a stand alone query to get the sum of FS by ID_T as follows:
SELECT tbl_Ts_base_atp.ID_T, Sum(tbl_Ts_mkv_atp.FS) AS SumOfFS
FROM tbl_Ts_base_atp INNER JOIN tbl_Ts_mkv_atp ON tbl_Ts_base_atp.ID_Ts = tbl_Ts_mkv_atp.ID_Ts
WHERE (((tbl_Ts_base_atp.DATE_T)>Date()-2000 And (tbl_Ts_base_atp.DATE_T)<Date()))
GROUP BY tbl_Ts_base_atp.ID_T, tbl_Ts_mkv_atp.ID_Ts;
I now want to match up the sum of FS from the second query to the records of the first query by ID_T. I realise I need to do this using a sub query. I'm confident using these when there's only one table but I consistently get 'syntax errors' when there are joins.
I simplified the first query down to remove all the WHERE conditions so it was easier for me to try and error check but no luck. I guess the resulting SQL will also be easier for you guys to follow:
SELECT today_atp.TOUR, (SELECT Sum(tbl_Ts_mkv_atp.FS)
FROM tbl_Ts_mkv_atp INNER JOIN (tbl_Ts_base_atp INNER JOIN today_atp ON tbl_Ts_base_atp.ID_T = today_atp.TOUR) ON tbl_Ts_mkv_atp.ID_Ts = tbl_Ts_base_atp.ID_Ts AS tt
WHERE tt.DATE_T>Date()-2000 And tt.DATE_T<Date() AND tt.TOUR=today_atp.TOUR
ORDER BY tt.DATE_T) AS SumOfFS
FROM today_atp
Can you spot where I'm going wrong? My hunch is that the issue is in the FROM line of the sub query but I'm not sure. Thanks in advance.
It's difficult to advise an appropriate solution without knowledge of how the database tables relate to one another, but assuming that I've correctly understood what you are looking to achieve, you might wish to try the following solution:
select
tours_atp.name_t,
today_atp.tour,
today_atp.id1,
odds_atp.k1,
today_atp.id2,
odds_atp.k2,
subq.sumoffs
from
(
(
(
(
today_atp inner join odds_atp on
today_atp.tour = odds_atp.id_t_o and
today_atp.id1 = odds_atp.id1_o and
today_atp.id2 = odds_atp.id2_o and
today_atp.round = odds_atp.id_r_o
)
inner join players_atp as players_atp_1 on
players_atp_1.id_p = today_atp.id2
)
inner join players_atp on
players_atp.id_p = today_atp.id1
)
inner join tours_atp on
today_atp.tour = tours_atp.id_t
)
inner join
(
select
tbl_ts_base_atp.id_t,
sum(tbl_ts_mkv_atp.fs) as sumoffs
from
tbl_ts_base_atp inner join tbl_ts_mkv_atp on
tbl_ts_base_atp.id_ts = tbl_ts_mkv_atp.id_ts
where
tbl_ts_base_atp.date_t > date()-2000 and tbl_ts_base_atp.date_t < date()
group by
tbl_ts_base_atp.id_t
) subq on
tours_atp.tour = subq.id_t
where
(tours_atp.rank_t between 1 and 4) and
today_atp.result = "" and
players_atp.name_p not like "*/*" and
players_atp_1.name_p not like "*/*" and
odds_atp.id_b_o = 2
order by
tours_atp.name_t;

SQL - select only newest record with WHERE clause

I have been trying to get some data off our database but got stuck when I needed to only get the newest file upload for each file type. I have done this before using the WHERE clause but this time there is an extra table involved that is needed to determine the file type.
My query looks like this so far and i am getting six records for this user (2x filetypeNo4 and 4x filetypeNo2).
SELECT db_file.fileID
,db_profile.NAME
,db_applicationFileType.fileTypeID
,> db_file.dateCreated
FROM db_file
LEFT JOIN db_applicationFiles
ON db_file.fileID = db_applicationFiles.fileID
LEFT JOIN db_profile
ON db_applicationFiles.profileID = db_profile.profileID
LEFT JOIN db_applicationFileType
ON db_applicationFiles.fileTypeID = > > db_applicationFileType.fileTypeID
WHERE db_profile.profileID IN ('19456')
AND db_applicationFileType.fileTypeID IN ('2','4')
I have the WHERE clause looking like this which is not working:
(db_file.dateCreated IS NULL
OR db_file.dateCreated = (
SELECT MAX(db_file.dateCreated)
FROM db_file left join
db_applicationFiles on db_file.fileID = db_applicationFiles.fileID
WHERE db_applicationFileType.fileTypeID = db_applicationFiles.FiletypeID
))
Sorry I am a noob so this may be really simple, but I just learn this stuff as I go on my own..
SELECT
ff.fileID,
pf.NAME,
ff.fileTypeID,
ff.dateCreated
FROM db_profile pf
OUTER APPLY
(
SELECT TOP 1 af.fileTypeID, df.dateCreated, df.fileID
FROM db_file df
INNER JOIN db_applicationFiles af
ON df.fileID = af.fileID
WHERE af.profileID = pf.profileID
AND af.fileTypeID IN ('2','4')
ORDER BY create_date DESC
) ff
WHERE pf.profileID IN ('19456')
And it looks like all of your joins are actually INNER. Unless there may be profile without files (that's why OUTER apply instead of CROSS).
What about an obvious:
SELECT * FROM
(SELECT * FROM db_file ORDER BY dateCreated DESC) AS files1
GROUP BY fileTypeID ;

Using some sort of loop in a subquery of SQL

I am making an SQL query in which I want to get some results for each latest entry of user, to do this I have made this query.
SELECT lA.attendance_id, lA.time_in, lA.time_out, lS.title, lS.end_time, lU.uid
FROM logi_attendance AS lA
INNER JOIN
logi_users AS lU ON lA.user_id = lU.user_id
INNER JOIN
logi_shifts AS lS ON lU.shift_id = lS.shift_id
WHERE
(lA.time_in IS NOT NULL) AND
(lA.time_out IS NULL) AND
(lA.attendance_id =
(
SELECT TOP (1) A.attendance_id
FROM logi_attendance AS A
INNER JOIN
logi_users AS B ON A.user_id = B.user_id
ORDER BY A.attendance_id DESC
)
)
As you can see I have used a subquery to retrieve the latest records of each user (new records are created on daily basis) so getting the latest record is requirement. Now see that I have used TOP(1) in subquery which restrict it to return 1 record only. This allows the main query to run successfully but it is not useful because it only returns record of one user which it finds first. But I want to get results of all users, but it should be done in a way that subquery returns each latest id one by one so the main query executes successfully. Right now if I remove TOP(1) then it gives me an error that subquery returns more than 1 value which is incorrect.
I don't know if I explained it properly, let me know if you don't understand what I am trying to ask and I will try to explain better.
Thanks.
You should be able to add
WHERE A.user_id = lA.user_id
to your sub-query. This would get you the most recent entry per user.
Not 100% sure of a solution but the reason it needs the TOP 1 is because you test lA.attendance_id = something and that something has to only be 1 result.
Try changing it to lA.attendance_id IN (select xxxxx) and that should get you more results.
Your subquery is not correlated. You need a correlated subquery, as follows:
SELECT lA.attendance_id, lA.time_in, lA.time_out, lS.title, lS.end_time, lU.uid
FROM logi_attendance AS lA
INNER JOIN
logi_users AS lU ON lA.user_id = lU.user_id
INNER JOIN
logi_shifts AS lS ON lU.shift_id = lS.shift_id
WHERE
(lA.time_in IS NOT NULL) AND
(lA.time_out IS NULL) AND
(lA.attendance_id =
(
SELECT TOP (1) A.attendance_id
FROM logi_attendance AS A
INNER JOIN
logi_users AS B ON A.user_id = B.user_id
--make it correlated:
WHERE A.user_id = lU.user_id
ORDER BY A.attendance_id DESC
)
)