Update using Distinct SUM - sql

I have found a few good resources that show I should be able to merge a select query with an update, but I just can't get my head around of the correct formatting.
I have a select statement that is getting info for me, and I want to pretty much use those results to Update an account table that matches the accountID in the select query.
Here is the select statement:
SELECT DISTINCT SUM(b.workers)*tt.mealTax as MealCost,b.townID,b.accountID
FROM buildings AS b
INNER JOIN town_tax AS tt ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
So in short I want the above query to be merged with:
UPDATE accounts AS a
SET a.wealth = a.wealth - MealCost
Where MealCost is the result from the select query. I am sure there is a way to put this into one, I just haven't quite been able to connect the dots to get it to run consistently without separating into two queries.

First, you don't need the distinct when you have a group by.
Second, how do you intend to link the two results? The SELECT query is returning multiple rows per account (one for each town). Presumably, the accounts table has only one row. Let's say that you wanted the average MealCost for the update.
The select query to get this is:
SELECT accountID, avg(MealCost) as avg_Mealcost
FROM (SELECT SUM(b.workers)*tt.mealTax as MealCost, b.townID, b.accountID
FROM buildings AS b INNER JOIN
town_tax AS tt
ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
) a
GROUP BY accountID
Now, to put this into an update, you can use syntax like the following:
UPDATE accounts
set accounts.wealth = accounts.wealth + asum.avg_mealcost
from (SELECT accountID, avg(MealCost) as avg_Mealcost
FROM (SELECT SUM(b.workers)*tt.mealTax as MealCost, b.townID, b.accountID
FROM buildings AS b INNER JOIN
town_tax AS tt
ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
) a
GROUP BY accountID
) asum
where accounts.accountid = asum.accountid
This uses SQL Server syntax, which I believe is the same as for Oracle and most other databases. Mysql puts the "from" clause before the "set" and allows an alias on "update accounts".

Related

How to display output when the Inner Select Query returns multiple values?

The inner Select returns multiple values which I am not able to display and getting error. The first select has multiple columns wherein one of the column values are fetched through an inner query which returns multiple values. I want all the inner select values.
select t.SiteId, t.Name, t.IsHoliday, t.DateStart, t.DateEnd, t.Year,
(
select count(te.Name), te.Name
from Term te
inner join Site_Program_Term spt on te.Id = spt.TermId
where te.Year = 2015 and te.SiteId = 2
group by te.Name
) from Term t where t.SiteId=2 and t.year=2015
You want a correlated subquery, not aggregation. I think this does what you want:
select t.SiteId, t.Name, t.IsHoliday, t.DateStart, t.DateEnd, t.Year,
(select count(*)
from Site_Program_Term spt
where t.Id = spt.TermId
)
from Term t
where t.SiteId = 2 and t.year = 2015;
In the way you are using the subquery you need to write it in a way only one record is selected. You can't have multiple results.
My suggestions is to run the subquery alone and check the results.
Based on that you should figure out which of all the records is the one you actually want, and see what condition your are missing for only that record to be selected.
The other alternative is that you are not thinking the query in the correct way.
More than one result in this kind of subqueries would be like trying to sit two people in the same seat at the same time.

SQL Server 2016 Sub Query Guidance

I am currently working on an assignment for my SQL class and I am stuck. I'm not looking for full code to answer the question, just a little nudge in the right direction. If you do provide full code would you mind a small explanation as to why you did it that way (so I can actually learn something.)
Here is the question:
Write a SELECT statement that returns three columns: EmailAddress, ShipmentId, and the order total for each Client. To do this, you can group the result set by the EmailAddress and ShipmentId columns. In addition, you must calculate the order total from the columns in the ShipItems table.
Write a second SELECT statement that uses the first SELECT statement in its FROM clause. The main query should return two columns: the Client’s email address and the largest order for that Client. To do this, you can group the result set by the EmailAddress column.
I am confused on how to pull in the EmailAddress column from the Clients table, as in order to join it I have to bring in other tables that aren't being used. I am assuming there is an easier way to do this using sub Queries as that is what we are working on at the time.
Think of SQL as working with sets of data as opposed to just tables. Tables are merely a set of data. So when you view data this way you immediately see that the query below returns a set of data consisting of the entirety of another set, being a table:
SELECT * FROM MyTable1
Now, if you were to only get the first two columns from MyTable1 you would return a different set that consisted only of columns 1 and 2:
SELECT col1, col2 FROM MyTable1
Now you can treat this second set, a subset of data as a "table" as well and query it like this:
SELECT
*
FROM (
SELECT
col1,
col2
FROM
MyTable1
)
This will return all the columns from the two columns provided in the inner set.
So, your inner query, which I won't write for you since you appear to be a student, and that wouldn't be right for me to give you the entire answer, would be a query consisting of a GROUP BY clause and a SUM of the order value field. But the key thing you need to understand is this set thinking: you can just wrap the ENTIRE query inside brackets and treat it as a table the way I have done above. Hopefully this helps.
You need a subquery, like this:
select emailaddress, max(OrderTotal) as MaxOrder
from
( -- Open the subquery
select Cl.emailaddress,
Sh.ShipmentID,
sum(SI.Value) as OrderTotal -- Use the line item value column in here
from Client Cl -- First table
inner join Shipments Sh -- Join the shipments
on Sh.ClientID = Cl.ClientID
inner join ShipItem SI -- Now the items
on SI.ShipmentID = Sh.ShipmentID
group by C1.emailaddress, Sh.ShipmentID -- here's your grouping for the sum() aggregation
) -- Close subquery
group by emailaddress -- group for the max()
For the first query you can join the Clients to Shipments (on ClientId).
And Shipments to the ShipItems table (on ShipmentId).
Then group the results, and count or sum the total you need.
Using aliases for the tables is usefull, certainly when you select fields from the joined tables that have the same column name.
select
c.EmailAddress,
i.ShipmentId,
SUM((i.ShipItemPrice - i.ShipItemDiscountAmount) * i.Quantity) as TotalPriceDiscounted
from ShipItems i
join Shipments s on (s.ShipmentId = i.ShipmentId)
left join Clients c on (c.ClientId = s.ClientId)
group by i.ShipmentId, c.EmailAddress
order by i.ShipmentId, c.EmailAddress;
Using that grouped query in a subquery, you can get the Maximum total per EmailAddress.
select EmailAddress,
-- max(TotalShipItems) as MaxTotalShipItems,
max(TotalPriceDiscounted) as MaxTotalPriceDiscounted
from (
select
c.EmailAddress,
-- i.ShipmentId,
-- count(*) as TotalShipItems,
SUM((i.ShipItemPrice - i.ShipItemDiscountAmount) * i.Quantity) as TotalPriceDiscounted
from ShipItems i
join Shipments s on (s.ShipmentId = i.ShipmentId)
left join Clients c on (c.ClientId = s.ClientId)
group by i.ShipmentId, c.EmailAddress
) q
group by EmailAddress
order by EmailAddress
Note that an ORDER BY is mostly meaningless inside a subquery if you don't use TOP.

Comparing two sum function in where clause

I want to check that an amount of likes the users received in all their personal pictures is at least twice as large as the number of likes received in the group pictures in which they are tagged.
In case the user is not tagged in any group photo but is tagged in a personal picture that has received at least one like, it will be returned.
My Question is:
How can I make a comparison between 2 sum functions
Where one result of the sum is returned in the nested query and compared with the external query.
Can I set an auxiliary variable to enter the sum value in it and compare it?
Thanks for the helpers:)
Select distinct UIP.userID
From tblUserInPersonalPic UIP
where **sum(UIP.numOfLikes) over (Partition by UIP.userID)*0.5** >
(Select distinct U.userID, sum(P.numOfLikes) over (Partition by U.userID)
From tblgroupPictures P left outer join
tblUserInGroupPic U On P.picNum=U.picNum
group by U.userID,P.numOfLikes,P.picNum)
It's kinda hard to know for sure, and of course I can't test my answer,
but I think you can do it with a couple of left joins, group by and having:
SELECT Personal.UserId
FROM tblUserInPersonalPic Personal
LEFT JOIN tblUserInGroupPic UserInGroup ON Personal.userID = UserInGroup.UesrId
LEFT JOIM tblgroupPictures GroupPictures ON UserInGroup.picNum = GroupPictures.picNum
GROUP BY Personal.userID
HAVING SUM(GroupPictures.numOfLikes) * 2 < SUM(Personal.numOfLikes)
Please note: When posting sql questions it's always best to provide sample data as DDL + DML (Create table + insert into statements) and desired results, so that who ever answers you can test the answer before posting it.
Try using two ctes..pseudo code.Also note distinct in second query will not even work,since you are returning two columns,so i changed it it below,so that you can get that column as well
;with tbl1
as
(
select a,sum(col1) as summ
from
tbl1
)
,tbl2
as
(
select userid,sum(Anothersmcol) as sum2
from tbl2
)
select tbl1.columns,tbl2.columns
from
tbl1 t1
join
tbl2 t2
on t1.sumcol>t2.sumcol
You can't use window functions in a where clause. Define it in a subquery:
select *
from (
select sum(...) over (...) as Sum1
, OtherColumn
from YourTable
) sub
where Sum1 < (...your subquery...)

Access Inner Join to select a record with the Max Date to distinctively select a record from another table

I am using Access and writing a query to join another table which has multiple records with the same ID. So, I only need to fetch the record with the MAX date to fetch only 1 record. I keep getting an syntax error.
Here is my normal Inner Join to the other table:
SELECT
table2.NameDesc,
FROM [table1]
INNER JOIN
(
SELECT [MyDataTable].[ID], [MyDataTable].[NameDesc], MAX( [MyDataTable].[MyDate]) as RecentDate
FROM [MyDataTable]
GROUP BY [MyDataTable].[ID]
) table2
ON [table1].[ID] = table2.[ID];
Normally on my inner join statement, I write like this:
INNER JOIN [table3] ON [table1].[ID] = [table3].[ID])
So I need to fetch only 1 record with the MAX date. I finally was able to
click save but when I click on the DateSheetView, I get the following error:
"Your query does not include the specified expression "NameDesc" as part of an aggregate function"
I am new the access query with the [ ] bracket which is different from sql server.
How can I get this Access query to work and fetch the record with the max date from another table?
Any help is appreaciated.
Thanks
When you use an aggregate function, like MAX, you need to include all other columns you are returning as part of the group by. In order for the query to run without errors, you can do this:
SELECT
table2.NameDesc
FROM [table1]
INNER JOIN
(
SELECT [MyDataTable].[ID],
[MyDataTable].[NameDesc],
MAX([MyDataTable].[MyDate]) as RecentDate
FROM [MyDataTable]
GROUP BY [MyDataTable].[ID],
[MyDataTable].[NameDesc]
) table2
ON [table1].[ID] = table2.[ID];

SQL / Teradata Query - Filter by fields while using multiple Inner Joins

I need to query my database and bring this back:
| Policy Num | Coverage Code |
My current query returns everything for the year 2014 ( i.e. A row for each claim number with the attached coverage code)
SELECT
SCHEMA.TABLE.POLICY_NUMBER,
P_FAR_BI_VW.V_CLAIM_SERVICE_TYP_DIM.COVERAGE_TYP_CDE
FROM
SCHEMA.TABLE
INNER JOIN SCHEMA.TABLE ON (SCHEMA.TABLE.POLICY_ID=SCHEMA.TABLE.POLICY_ID)
INNER JOIN SCHEMA.TABLE ON (SCHEMA.TABLE.SERVICE_TYPE_ID=SCHEMA.TABLE.SERVICE_TYPE_ID)
INNER JOIN SCHEMA.TABLE ON (SCHEMA.TABLE.FISCAL_PERIOD_ID=SCHEMA.TABLE.FISCAL_PERIOD_ID AND SCHEMA.TABLE.YEAR_NUM = 2014)
I have tried a few different ways of querying but I can't seem to get it to work. I have tried:
SELECT
distinct(SCHEMA.TABLE.POLICY_NUMBER),
SCHEMA.TABLE.COVERAGE_TYP_CDE
Inner Joins
group by
SCHEMA.TABLE.COVERAGE_TYP_CDE
and other various ideas. The Error I am getting in return is: Selected non-aggregate values must be part of the associated group
I know there must be away to
Your select items must all be in your group by
SELECT distinct(SCHEMA.TABLE.POLICY_NUMBER)
, SCHEMA.TABLE.COVERAGE_TYP_CDE
/* INNER JOINS */
GROUP BY SCHEMA.TABLE.POLICY_NUMBER
, SCHEMA.TABLE.COVERAGE_TYP_CDE;