Implements select statement in update clause in SQL - sql

I want to write an update SQL statement, which implements a select statement with join and group by another table.
Something like:
UPDATE coaches *******
here I would like to implement SELECT statement below:
SET coach_level = coach_level +1
This statement works correctly, but I really don't know how to use it in update statement:
SELECT c.first_name,c.coach_level,COUNT(pc.coach_id)
FROM coaches AS c
JOIN players_coaches AS pc
ON c.id = pc.coach_id
GROUP BY pc.coach_id
HAVING COUNT(pc.coach_id) >= 1 AND c.first_name LIKE 'A%';
I want to return the increased value of coach_level by one, which is a column from table coaches.
Like this:
SET coach_level= coach_level +1
Does anybody know how should I do this?
Thanks in advance!

Aggregate in the table players_coaches and join to coaches:
UPDATE coaches AS c
INNER JOIN (
SELECT coach_id
FROM players_coaches
GROUP BY coach_id
HAVING COUNT(*) >= 1
) AS pc ON pc.coach_id = c.id
SET c.coach_level = coach_level + 1
WHERE c.first_name LIKE 'A%'
This is MySql syntax. It can be modified if you use another rdbms.

Use where clause:
update coaches
set coach_level = coach_level + 1
where id in (select pc.coach_id
from player_coaches pc
group by pc.coach_id
having count(*) >= 1
) and
first_name like 'A%';
That said, your subquery is just checking if any row exists for the coachin player_coaches. This can be simplified to:
update coaches
set coach_level = coach_level + 1
where exists (select pc.coach_id
from player_coaches pc
where pc.coach_id = coaches.id
) and
c.first_name like 'A%';

Related

SQL query to retrieve last record from a linked table [duplicate]

This question already has answers here:
SQL join: selecting the last records in a one-to-many relationship
(13 answers)
Closed 6 years ago.
I wrote a query to compare 2 columns in different tables (TRELAY VS TUSERDEF8). The query works great, except that it retrieves the top record in the TUSERDEF8 table which has a many to one relationship to the TRELAY table.
The tables are linked by TRELAY.ID = TUSERDEF8.N01. I would like to retrieve the latest record from TUSERDEF8 and compare that record with the TRELAY record. I plan to use the max value of the index column (TUSERDEF8.ID) to determine the latest record.
I am using SQL Server.
My code is below, but I'm not sure how to change the query to retrieve the last TUSERDEF8 record. Any help is appreciated.
SELECT
TRELAY.ID, TRELAY.S15,
TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM
TRELAY
INNER JOIN
TUSERDEF8 ON TRELAY.ID = TUSERDEF8.N01
WHERE
LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (TRELAY.S15 LIKE '%MEDIUM%' AND
TUSERDEF8.S04 LIKE '%N/A%' AND
TUSERDEF8.S06 LIKE '%EACMS%')
Making the assumption that your IDs are int(s) then the below might work?
SELECT TOP 1 TRELAY.ID, TRELAY.S15, TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM TRELAY INNER JOIN TUSERDEF8
ON TRELAY.ID = TUSERDEF8.N01
WHERE LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (
TRELAY.S15 LIKE '%MEDIUM%'
AND TUSERDEF8.S04 LIKE '%N/A%'
AND TUSERDEF8.S06 LIKE '%EACMS%'
)
ORDER BY TUSERDEF8.ID DESC
HTH
Dave
You could do this:
With cteLastRecord As
(
Select S04, N01, S06,
Row_Number() Over (Partition By N01, Order By ID Desc) SortOrder
From TUSERDEF8
)
SELECT
TRELAY.ID, TRELAY.S15,
TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM
TRELAY
INNER JOIN
(Select S04, N01, S06 From cteLastRecord Where SortOrder = 1) TUSERDEF8 ON TRELAY.ID = TUSERDEF8.N01
WHERE
LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (TRELAY.S15 LIKE '%MEDIUM%' AND
TUSERDEF8.S04 LIKE '%N/A%' AND
TUSERDEF8.S06 LIKE '%EACMS%')
I believe that your expected output is still a little ambiguous.
It sounds to me like you want only the record from the output where TUSERDEF8.ID is at its max. If that's correct, then try this:
SELECT TRELAY.ID, TRELAY.S15, TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM TRELAY
INNER JOIN TUSERDEF8 ON TRELAY.ID = TUSERDEF8.N01
WHERE LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (TRELAY.S15 LIKE '%MEDIUM%' AND
TUSERDEF8.S04 LIKE '%N/A%' AND
TUSERDEF8.S06 LIKE '%EACMS%')
AND TUSERDEF8.ID IN (SELECT MAX(TUSERDEF8.ID) FROM TUSERDEF8)
EDIT: After reviewing your recent comments, it would seem something like this would be more suitable:
SELECT
, C.ID
, C.S15,
, D.S04
, D.N01
, D.S06
FROM (
SELECT A.ID, A.S15, MAX(B.ID) AS MaxID
FROM TRELAY AS A
INNER JOIN TUSERDEF8 AS B ON A.ID = B.N01
WHERE
LEFT(A.S15, 1) <> LEFT(B.S04, 1)
AND NOT (A.S15 LIKE '%MEDIUM%' AND
B.S04 LIKE '%N/A%' AND
B.S06 LIKE '%EACMS%')
GROUP BY A.ID, A.S15
) AS C
INNER JOIN TUSERDEF8 AS D ON C.ID = D.N01 AND C.MaxID = D.ID
Using an ID column to determine which row is "last" is a bad idea
Using cryptic table names like "TUSERDEF8" (how is it different from TUSERDEF7) is a very bad idea, along with completely cryptic column names like "S04".
Using prefixes like "T" for table is a bad idea - it should already be clear that it's a table.
Now that all of that is out of the way:
SELECT
R.ID,
R.S15,
U.S04,
U.N01,
U.S06
FROM
TRELAY R
INNER JOIN TUSERDEF8 U ON U.N01 = R.ID
LEFT OUTER JOIN TUSERDEF8 U2 ON
U2.N01 = R.ID AND
U2.ID > U.ID
WHERE
U2.ID IS NULL AND -- This will only happen if the LEFT OUTER JOIN above found no match, meaning that the row in U has the highest ID value of all matches
LEFT(R.S15, 1) <> LEFT(U.S04, 1) AND
NOT (
R.S15 LIKE '%MEDIUM%' AND
U.S04 LIKE '%N/A%' AND
U.S06 LIKE '%EACMS%'
)

Link all query (select and delete) in one

I am trying to make one statement(automated) of the following queries.
All i know proposal id from my UI. i do query manually like below
select * from tblAssessment where ProposalID like '%0081/2013/0587B%'
select * from tblAssessmentVersion where AssessmentID=587
select * from tblIdentifiedThreatenedSpecies where AssessmentVersionID=731
delete from tblIdentifiedThreatenedSpecies where PercentGain=0 and AssessmentVersionID=731
once i know the proposal id ,i query in to tblassessment to get the assessment id then use the assessment id to query in to assessmentversion table to find the assessment version ID then use the assessment version id in to Identified species table to delete the record where percentgain column is 0.
Appreciate all your help,thanks in advance
You can use DELETE FROM .. JOIN:
DELETE s
FROM tblIdentifiedThreatenedSpecies s
INNER JOIN tblAssessmentVersion v
ON v.AssessmentVersionID = s.AssessmentVersionID
INNER JOIN tblAssessment a
ON a.AssessmentID = v.AssessmentID
WHERE
a.ProposalID LIKE '%0081/2013/0587B%'
AND PercentGain = 0
To check for rows to be deleted, SELECT first:
SELECT s.*
FROM tblIdentifiedThreatenedSpecies s
INNER JOIN tblAssessmentVersion v
ON v.AssessmentVersionID = s.AssessmentVersionID
INNER JOIN tblAssessment a
ON a.AssessmentID = v.AssessmentID
WHERE
a.ProposalID LIKE '%0081/2013/0587B%'
AND PercentGain = 0
join all your SELECT in one subquery
delete from tblIdentifiedThreatenedSpecies
where PercentGain=0 and AssessmentVersionID in
(
select av.Id
from
tblAssessmentVersion av
join tblAssessment a on a.Id = av.AssessmentID
where a.ProposalID like '%0081/2013/0587B%'
)
I hope this will work.
delete from tblIdentifiedThreatenedSpecies
where PercentGain=0 and AssessmentVersionID=(
select top 1 AssessmentVersionID from tblAssessmentVersion where AssessmentID=(
select top 1 AssessmentID from tblAssessment where ProposalID like '%0081/2013/0587B%'
)
);
Here top 1 is used if query returns more than one records, which is optional it your query doesn't.
Thank you.

Selective update in SQL Server

I've created a junction table like this one:
http://imageshack.us/scaled/landing/822/kantotype.png
I was trying to figure out a query that could able to select some rows - based on the PokémonID - and then updating only the first or second row after the major "filtering".
For example:
Let's suppose that I would like to change the value of the TypeID from the second row containing PokémonID = 2. I cannot simply use UPDATE KantoType SET TypeID = x WHERE PokémonID = 2, because it will change both rows!
I've already tried to use subqueries containing IN,EXISTS and LIMIT, but with no success.
Its unclear what are your trying to do. However, you can UPDATE with JOIN like so:
UPDATE
SET k1.TypeID = 'somethng' -- or some value from k2
FROM KantoType k1
INNER JOIN
(
Some filtering and selecting
) k2 ON k1.PokémonID = k2.PokémonID
WHERE k1.PokémonID = 2;
Or: if you want to UPDATE only the two rows that have PokémonID = 2 you can do this:
WITH CTE
AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY TypeID) rownum
FROM KantoType
WHERE PokemonID = 2
)
UPDATE c
SET c.TypeID = 5
FROM CTE c
WHERE c.rownum = 1;
SQL Fiddle Demo
I can suggest something like this if you just need to update a single line in your table:
UPDATE kantotype
SET
type = 2
WHERE pokemon = 2
AND NOT EXISTS (SELECT * FROM kantotype k2
WHERE kantotype.type > k2.type
AND kantotype.pokemon = k2.pokemon)
It would be easier to get the first or last item of the table if you had unique identifier field in your table.
Not sure even if you are trying to update the row with PokemenID =2 by doing a major filtering on TypeID... So just out of assumptiong (big one), you can give a try on Case
UPDATE yourtable a
LEFT JOIN youtable b on a.pokeid = b.pokeid
SET a.typeid = (CASE
WHEN a.typeid < b.typeid THEN yourupdatevalue
WHEN a.typeid > b.typeid THEN someothervalue
ELSE a.typeid END);
If you know the pokemon ID and the type id then just add both to the where clause of your query.
UPDATE KantoType
SET TypeID = x
WHERE PokémonID = 2
AND TypeID=1
If you don't know the type ID, then you need to provide more information about what you're trying to accomplish. It's not clear why you don't have this information.
Perhaps think about what is the unique identifier in your data set.

SQL Select Where or Having

Im attempting to get some records from a table based on certain factors.
One of the factors is simply with fields on the same table, the other is when joining to another table, I want to compare the number of records in the joined table to a field on the first table. Below is a sample code.
select * from tDestinations D
left join tLiveCalls LC on LC.DestinationID = D.ID
where D.ConfigurationID = 1486
AND (D.Active = 1 AND D.AlternateFail > GETDATE())
-- Having COUNT(LC.ID) = D.Lines
Now from the code above I cant have the Count function in the where clause, and I cant have a field in in the having clause without it being in a function.
Im probably missing something very simple here. But I cant figure it out.
Any help is appreciated it.
EDIT: I do apologise should have explained the structure of the tables, the Destinations are single records, which the LiveCalls table can hold multiple records based on the Destinations ID (foreign key).
Thank you very much for everyones help. My final code:
select D.ID, D.Description, D.Lines, D.Active, D.AlternateFail, D.ConfigurationID, COUNT(LC.ID) AS LiveCalls from tDestinations D
left join tLiveCalls LC on LC.DestinationID = D.ID
where D.ConfigurationID = #ConfigurationID
AND (D.Active = 1 AND D.AlternateFail > GETDATE())
GROUP BY D.ID, D.Description, D.Lines, D.Active, D.AlternateFail, D.ConfigurationID
HAVING COUNT(LC.ID) <= D.Lines
The simple thing you're missing is the GROUP BY statement.
As JNK mentioned in the comments below, you cannot use an aggregate function (such as COUNT, AVG, SUM, MIN) if you don't have a GROUP BY clause, unless your SELECT statement only references literal values (and no column names).
Your code should probably be something like:
SELECT <someFields>
FROM tDestinations D
LEFT JOIN tLiveCalls LC on LC.DestinationID = D.ID
WHERE D.ConfigurationID = 1486
AND (D.Active = 1 AND D.AlternateFail > GETDATE())
GROUP BY <someFields>
HAVING COUNT(LC.ID) = D.Lines
Note that you have to specify the selected fields explicitely, in both the SELECT and GROUP BY statements (no * allowed).
you can only use having with aggregations. Actually having is the "where clause" for aggregation, BUT you can still have a where on the columns that you are no aggregating.
For example:
SELECT TABLE_TYPE, COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
where TABLE_TYPE='VIEW'
group by TABLE_TYPE
having COUNT(*)>1
In your case you need to use havving count(*)=1
so, I think your query would be something like this:
select YOUR_COLUMN
from tDestinations D
left join tLiveCalls LC on LC.DestinationID = D.ID
where D.ConfigurationID = 1486 AND (D.Active = 1 AND D.AlternateFail > GETDATE())
group by YOUR_COLUMN
Having COUNT(LC.ID) = value

Update in child table, only one value got updated

Below I am trying to update value of a parent table from child table and counting matching values. Tables in my db:
issue_dimension with id = issue_id and have column accno.
star_schema with id star_id,this Child column have fk issue_id and column book_frequency
The book_frequency need to match the count of each accno in parent table , I tried this
update [test1] .[dbo] .star_schema
set [book_frequency] = (
select top 1 COUNT([issue_dimension].ACCNO)as book_frequency
from issue_dimension
group by ACCNO having (COUNT(*)>1) and
issue_dimension.ACCNO = star_schema .ACCNO
)
It only updates only 1st value count issue_dimension. I need to count every accno in issue_dimension and update it to matching accno of star_schema.
I never did update by joining two or more tables , can anyone help in this with joins
UPDATE s
SET [book_frequency] = i.CNT
FROM [test1].[dbo].star_schema s
INNER JOIN
(
SELECT ACCNO, COUNT(*) as CNT
FROM issue_dimension
GROUP BY ACC_NO
HAVING COUNT(*)>1
) i on (s.ACCNO = i.ACCNO)
I didn't check it but it should works
Try in this way, without grouping, just with the WHERE clause:
UPDATE [test1].[dbo].star_schema SET
[book_frequency] =
(
SELECT COUNT([issue_dimension].ACCNO)
FROM issue_dimension
WHERE issue_dimension .ACCNO = star_schema.ACCNO
HAVING COUNT(*)>1
)
It's not fully clear to me so the answer is a bit of guessing:
update s set
book_frequency = t.qty
from star_schema s
join issue_dimension i on s.issue_id = s.issue_id
join (select count(*) as qty, accno
from issue_dimension
group by accno
) t on i.accno = t.accno
Here's the example from BOL that does the kind of thing you're looking for, using AW:
USE AdventureWorks2008R2;
GO
UPDATE Sales.SalesPerson
SET SalesYTD = SalesYTD +
(SELECT SUM(so.SubTotal)
FROM Sales.SalesOrderHeader AS so
WHERE so.OrderDate = (SELECT MAX(OrderDate)
FROM Sales.SalesOrderHeader AS so2
WHERE so2.SalesPersonID = so.SalesPersonID)
AND Sales.SalesPerson.BusinessEntityID = so.SalesPersonID
GROUP BY so.SalesPersonID);