update table using another table - sql

i have to update total_orders of customers column to be equal to the total number of all the orders placed by the customer(in cust_order)
here is what i have tried
update (select *
from atish_customer a
inner join
(
select cust_nbr,count(cust_nbr) as count_orders
from atish_cust_order
group by cust_nbr
)c
on c.cust_nbr=a.cust_nbr)
set tot_orders=count_orders;
But this is the error i get
ORA-01779: cannot modify a column which maps to a non key-preserved table

How about this:
UPDATE customer SET total_orders = (
SELECT COUNT(*) FROM cust_order
WHERE cust_order.cust_nbr = customer.cust_nbr
)
[I'm not sure where your atish_customer and atish_customer_order comes into play...they're not shown in your diagram]
Explanation: Basically the inner select just counts the number of orders from the cust_order table for each cust_nbr. By joining the outer customer.cust_nbr to the inner cust_order.cust_nbr, each [outer] row will be updated with the correct total. This is called a correlated subquery (see here for a short tutorial).

Related

SQL dividing a count from one table by a number from a different table

I am struggling with taking a Count() from one table and dividing it by a correlating number from a different table in Microsoft SQL Server.
Here is a fictional example of what I'm trying to do
Lets say I have a table of orders. One column in there is states.
I have a second table that has a column for states, and second column for each states population.
I'd like to find the order per population for each sate, but I have struggled to get my query right.
Here is what I have so far:
SELECT Orders.State, Count(*)/
(SELECT StatePopulations.Population FROM Orders INNER JOIN StatePopulations
on Orders.State = StatePopulations.State
WHERE Orders.state = StatePopulations.State )
FROM Orders INNER JOIN StatePopulations
ON Orders.state = StatePopulations.State
GROUP BY Orders.state
So far I'm contending with an error that says my sub query is returning multiple results for each state, but I'm newer to SQL and don't know how to overcome it.
If you really want a correlated sub-query, then this should do it...
(You don't need to join both table in either the inner or outer query, the correlation in the inner query's where clause does the 'join'.)
SELECT
Orders.state,
COUNT(*) / (SELECT population FROM StatePopulation WHERE state = Orders.state)
FROM
Orders
GROUP BY
Orders.state
Personally, I'd just join them and use MAX()...
SELECT
Orders.state,
COUNT(*) / MAX(StatePopulation.population)
FROM
Orders
INNER JOIN
StatePopulation
StatePopulation.state = Orders.state
GROUP BY
Orders.state
Or aggregate your orders before you join...
SELECT
Orders.state,
Orders.order_count / StatePopulation.population
FROM
(
SELECT
Orders.state,
COUNT(*) AS order_count
FROM
Orders
GROUP BY
Orders.state
)
Orders
INNER JOIN
StatePopulation
StatePopulation.state = Orders.state
(Please forgive typos and smelling pistakes, I'm doing this on a phone.)

How can I perform this sql update using sql instead of using code?

I have been able to select this data, using these two sql queries
Query 1:
SELECT article_id, amount_required, amount_sold FROM products_articles,sales WHERE sales.product_id = products_articles.product_id
Query 2:
SELECT * FROM articles
What I want to do, is go through the first table (with amount sold and required) (it's fine that there are duplicate rows), and for each row in the table multiply the value of amount_sold and amount_required and then subtract that value from amount_in_stock where the ids match in the second table.
Example from the first row:
2 * 4 = 8, change amount_in_stock from 124 to 116.
And so on...
How can I do this using just sql?
UPDATE A
SET
A.amount_in_stock =(S.amountSold * S.amount_required)- A.amount_in_stock
FROM articles AS A
INNER JOIN
products_articles AS PA
ON PA.article_id= A.article_id
INNER JOIN Sales AS S
ON S.product_id=PA.product_id
Please try this:
Update articles a
inner join
(
SELECT article_id, sum(amount_required) amount_required, sum(amount_sold )amount_sold FROM products_articles inner join sales on sales.product_id = products_articles.product_id
group by article_id
)b on a.article_id=b.article_id
set a.amount_in_stock=a.amount_in_stock-(amount_required*amount_sold )
Since there could be multiple rows in product_articles and amount_sold I have used group by to sum the amounts.
For SQLite please try this:
Update articles
set amount_in_stock=(SELECT sum(amount_required) * sum(amount_sold ) FROM products_articles inner join sales on sales.product_id = products_articles.product_id
where products_articles.article_id=articles.article_id
group by article_id
)
where exists (SELECT * FROM products_articles inner join sales on sales.product_id = products_articles.product_id where products_articles.article_id=articles.article_id
)

SQL joined tables are causing duplicates

So table A is an overall table of policy_id information, while table b is policy_id's with claims attached. Not all of the id's in A exist in B, but I want to join the two tables and sum(total claims).
The issue is that the sum is way higher than the actual sum within the table itself.
Here is what I've tried so far:
select a.policy_id, coalesce(sum(b.claim_amt), 0)
from database.table1 as a
left join database2.table2 as b on a.policy_id = b.policy_id
where product_code = 'CI'
group by a.policy_id
The id's that don't exist in b show up just fine with a 0 next to them, it's the ones that do exist where the claim_amt's seem like they're being duplicated heavily in the sum.
I suspect your policy_id in table1 are not unique and that leads to the doubled,tripled ,etc. amounts
You could aggregate the sums from table2 in a CTE to get around this.
WITH CTE AS (
SELECT
policy_id
coalesce(sum(claim_amt), 0) as sum_amt
FROM database2.table2
group by policy_id
)
select a.policy_id, b.sum_amt
from database.table1 as a
left join CTE as b on a.policy_id = b.policy_id
where product_code = 'CI'

How to display last updated record for multiple records

I have joined two tables to pull the data I need. I'm having trouble only displaying the most current record from one table. What I'm trying to do is look for the last updated value. I have tried to incorporate max() and row_num but have not had any success.
Here is what I currently have:
select distinct t1.CaId,t1.Enrolled,t1.Plan,t2.Category,t2.updateddate
from table.one(nolock) t1
inner join table.two(nolock) t2 on t1.CaId=t2.CaID
where t1.coverageyear=2016
and right(t1.Plan,2)<>left(t2.Category,2)
order by 5 desc
You can join your main query with a subquery that just grabs the last update date for each ID, like this:
select all_rec.CaId, all_rec.Enrolled, all_rec.[Plan], all_rec.Category, all_rec.updateddate
from
(select distinct t1.CaId,t1.Enrolled,t1.[Plan],t2.Category,t2.updateddate
from [table.one](nolock) t1
inner join [table.two](nolock) t2 on t1.CaId=t2.CaID
where t1.coverageyear=2016
and right(t1.[Plan],2)<>left(t2.Category,2)
) as all_rec
inner join
(SELECT max(updateddate) AS LAST_DATE, CaId
FROM [table.two](nolock)
GROUP BY CaId)
AS GRAB_DATE
on (all_rec.Ca_Id = GRAB_DATE.Ca_Id)
and (all_rec.updateddate = GRAB_DATE.updateddate)
order by 5 desc
I added brackets around your usages of table and Plan because those are SQL reserved words.
If you are trying to get last updated value, then just simply add to your query:
order by t2.updateddate desc
It will show most current record from tables.

How can I SELECT a result set of data from a single table with one of the columns coming from the SUM of a column in a different table?

So let's say I want 5 columns total in my result set, for example:
Name, Date, Color, Price, TotalSales
Name, Date, Color, and Price are all stored in a single table so I will just get every row from that table.
SELECT * FROM AwesomeStuff
However, TotalSales needs to be calculated from the SUM of values in another table, and the values that needed to be combined must match up with the ID of the row from the AwesomeStuff table.
SELECT SUM(SalePrice) FROM AwesomeSales
Each row in the AwesomeSales table has an ID that matches a single item in the AwesomeStuff table. So I want to add up all the SalePrice values into a single column and match it up with the correct row in the AwesomeStuff query so I get back the single result set.
How does this work? Along with the query, can you explain what SQL is doing in plain english so I can understand how to write this type of SELECT again in the future?
Thanks.
You can perform a GROUP BY operation to group the results per "AwesomeStuff" item:
SELECT
A.Name,
A.Date,
A.Color,
A.Price,
SUM(S.SalePrice) AS TotalSales
FROM
AwesomeStuff A
INNER JOIN
AwesomeSales S
ON
S.AwesomeStuffId = A.Id
GROUP BY
A.Name,
A.Date,
A.Color,
A.Price
select
t.name,
t.date,
t.color,
t.price,
a.TotalSales
from awesomestuff t
inner join
(
select id, sum(saleprice) as TotalSales
from awesomesales
group by id
)a
on t.id = a.id
What this does is calculates the SUM() based on each id. And then with an inner join it creates the relationship for the TotalSales per id to show in the result set.
The SQL to do what you want is:
select AwesomeStuff.Name,
AwesomeStuff.Date,
AwesomeStuff.Color,
AwesomeStuff.Price,
AwesomeStuff.TotalSales,
TotalSales.Price
from AwesomeStuff
join (select AwesomeSales.id,
sum(AwesomeSales.SalePrice) As Price
from AwesomeSales
group by id) As TotalSales
on TotalSales.id = AwesomeStuff.id;
I will update this post after lunch with an English explanation.
English You aggregate the sale prices, taking the sum, grouped by their ID. This is what the inline view (sub-query) does: we include the ID because we need to use it in the join. That is we join your AwesomeStuff table with the inline view of sales (aliased as TotalSales, as we refer to it later), match them by ID -- as this is the primary key -- and then select all the fields (including the calculated sum, which we have aliased as Price) together.
You could use a subquery if your Database supports it:
SELECT stuff.Name, stuff.Date, stuff.Color, stuff.Price, sales.total
FROM AwesomeStuff AS stuff,
(SELECT STUFF_ID, SUM(SalePrice) AS total
FROM AwesomeSales
GROUP BY STUFF_ID) AS sales
where stuff.ID = sales.STUFF_ID
SELECT
a.Name,
a.Date,
a.Color,
a.Price,
SUM(s.SalesPrice)
FROM AwesomeStuff as a
INNER JOIN AwesomeSales as s on a.ID = s.AwesomestuffID
GROUP BY a.Name, a.Date, a.Color, a.Price
In plain English, what you are doing is saying give me all the unique combinations of name, date, color and price from your stuff table and a sum of all the sales from the sales table. This assumes that each ID in the stuff table represents a unique combination of name, date, color and price.
Try:
SELECT A.Id, -- not required in select for query to work - included for clarity
max(A.Name),
max(A.Date),
max(A.Color),
max(A.Price),
SUM(S.SalePrice) AS TotalSales
FROM AwesomeStuff A
LEFT JOIN AwesomeSales S ON S.AwesomeStuffId = A.Id
GROUP BY A.Id
By joining AwesomeStuff to AwesomeSales on the product's unique ID, you will get a row returned for every sale of every product - since you only want one row per product, you need to group by the product's unique ID. (The SUM function should be self-explanatory.)
Unfortunately, most forms of SQL will not allow you to include unaggregated values in a grouped query, even where these are functionally dependant on one of the values that is being grouped - as in this query. This is why name, date, color and price have all been MAXed.
A left join ensures that records on the left-hand side of the join (here, AwesomeStuff) will be returned even if there are no corresponding records on the right-hand side of the join (AwesomeSales). In other words, this version of the query will include products that have had no sales.