SQL - Set field as count from another table - sql

I am trying to set a field in my target table as the count of the email addresses in another table. An email address can appear many times in my other table and I wanted to count the total up and set that count as my target field value.
SELECT
a.*
,a.PickedUp_Count AS COUNT(b.Emailaddress)
FROM
Master_List a
INNER JOIN
Picked_Up b
ON
a.Emailaddress = b.Emailaddress

It's best not to use * selectors because usually you want to know specifically what you're getting back from a table. You don't have to expand it in the select, but you DO have to identify how all of the individual columns will also be aggregated in the group by column.
SELECT
a.<field1>
a.<field2>
....
,COUNT(*) as PickedUp_Count
FROM
Master_List a
INNER JOIN Picked_Up b
ON a.Emailaddress = b.Emailaddress
GROUP BY
<field1>
,<field2>
....
The group by must include all fields listed in the select which are not already being aggregated in the select - i.e. any field that isn't the count.
Additionally, it's worth noting that PickedUp_Count is whatever random name you choose.

Related

Comparing 3 tables in an Access Database

I am trying to compare a series of tables within an access database, 2 local and one linked.
Table A (local) contains UserID, Title, Position; Table B (linked) contains UserID, Title, and Position from the previous week (records could possibly change on a week to week basis); Table C (local) contains UNIQUE UserID's and Titles.
I need to ensure that all UserID's contained in Table C still exist
in Table A.
I need to ensure that all UserID's contained in Table C have not had
a change in Title or Position from the previous week. If so Add to a temp table.
I'd prefer to use Access VBA or SQL in accomplish this task and the information will be displayed in a report.
Basically the same logic for both examples. use a left join to to identify mismatches.
Identify missing users in A
Insert into TableA (userID,Title)
select TableC.UserID, TableC.Title
from TableC
left join TableA on TableC.UserID=TableA.UserID
where TableA.UserID is null
Identify changes from B to A
insert into temp (userID,title,position)
select c.userID,c.title,c.position
from TableA a
left join tableB b on b.userid=a.userID and b.title=a.title and b.position=a.position
where b.userID is null

Scalar subquery contains more than one row

Im working with H2 database and wanted to move some data. For that I created the following Query:
UPDATE CUSTOMER
SET EMAIL = SELECT service.EMAIL
FROM CUSTOMER_SERVICE AS service
INNER JOIN CUSTOMER AS customer ON service.ID = customer.CUSTOMER_SERVICE_ID;
When I now perform it in the H2 console I get the following error:
Scalar subquery contains more than one row; SQL statement:
UPDATE CUSTOMER
SET EMAIL = SELECT service.EMAIL
FROM CUSTOMER_SERVICE AS service
INNER JOIN CUSTOMER AS customer ON service.ID = customer.CUSTOMER_SERVICE_ID [90053-192] 90053/90053 (Hilfe)
What is this error telling me?
EDIT
What I want to achiev with my query:
Actually every CUSTOMER has a CUSTOMER_SERVICE. And I simply want to move the COLUMN EMAIL from CUSTOMER_SERVICE to the CUSTOMER Table. for that I already added a email column to the user. I hoped to be able to do it with my query but obviously not.
Your query is not syntactically valid (all subqueries must have parentheses around them).
What you are missing is a correlation clause. I believe you want:
UPDATE CUSTOMER c
SET EMAIL = (SELECT cs.EMAIL
FROM CUSTOMER_SERVICE s
WHERE s.ID = c.CUSTOMER_SERVICE_ID
);
I don't know what this is supposed to be: [90053-192] 90053/90053 (Hilfe).
Your select query is returning more than one row. If you don't want it to, then you need to do something like an aggregate or LIMIT 1 or something similar.
Your sub-query for at least one of your customers has multiple email addresses.
You could ... (Select top 1 serverice.email ...
Or ... (Select max(serverice.email) ...
Update Customer Set EMail=B.Email
From Customer A
Join (Select ID,max(EMail) as EMail From CUSTOMER_SERVICE Group By ID) B
on (A.CUSTOMER_SERVICE_ID = B.ID)
I've spend a lot time with this error type (there shoudn't be duplicates in DB).
At last I've found problem via SQL with COUNT like this:
UPDATE CUSTOMER
SET EMAIL = SELECT COUNT(service.EMAIL)
FROM CUSTOMER_SERVICE AS service
INNER JOIN CUSTOMER AS customer ON service.ID =
customer.CUSTOMER_SERVICE_ID;
And then select problem rows with EMAIL!='1'

How I use where clause with computed column to get related records only

I read this FAQ http://www.firebirdfaq.org/faq289/ and I want to use select to count detail record from current record so I tried this
((
select count(*) from detail_table where detail_table.id = id
))
But I did not get correct values I got numbers like 19 where in fact it is the total number of records in detail_table! How can I get only the count of records related to current master record in master table?
The problem is that id refers to the id column of detail_table and not of the master table. So it is the equivalent of:
select count(*) from detail_table where detail_table.id = detail_table.id
Which means you are simply counting all rows. Instead - assuming the master table is master_table - you should use:
select count(*) from detail_table where detail_table.id = master_table.id
Note that, as also mentioned in the FAQ you link to, you should really consider using a view instead of a computed column when referencing other tables as it is not very good for performance.
The view equivalent would be something like
CREATE OR ALTER VIEW master_with_detail_count
AS
SELECT master_table.id, coalesce(c.detail_count, 0) as detail_count
FROM master_table
LEFT JOIN (SELECT id, count(*) as detail_count FROM detail GROUP BY id) c
ON c.id = master.id

how to query access to select entire records given a distinct criteria

I want to select the entire first row of each record where a promo code is unique. I am trying to create a samples table, in this table will be one record (the first record) from each distinct promo code. I have asked all of my co-workers and they usually go though the data by hand and select one from each. the problem is that the number of promo codes grows each time and the codes change. so I want to write a query that will select the first record found to have each distinct code. so for I have something like this:
SELECT DISTINCT Customer.promo1 FROM Customer AS promo;
SELECT * FROM Customer, promo
WHERE Customer.promo1 = promo.promo1;
But this obviously give the original table. I do have a ID field called AutoID in Customer.
Thanks in advance.
I'm assuming you want the first Customer.AutoId associated with each Customer.Promo
SELECT
c.*
FROM
Customer c
INNER JOIN
(
SELECT
c.promo1,
MIN(c.AutoID) AutoID
FROM
Customer c
GROUP BY
c.promo1) FirstCusomterWithPromo
ON c.AutoID = FirstCusomterWithPromo.AutoID
Something like that:
SELECT * FROM Customer
GROUP BY Customer.promo1

Some SQL Questions

I have been using SQL for years, but have mostly been using the query designer within SQL Studio (etc.) to put together my queries. I've recently found some time to actually "learn" what everything is doing and have set myself the following fairly simple tasks. Before I begin, I'd like to ask the SOF community their thoughts on the questions, possible answers and any tips they may have.
The questions are;
Find all records w/ a duplicate in a particular column (e.g. a linking id is in more than 1 record throughout table)
SUM price from a linked table within the same query (select within a select?)
Explain the difference between the 4 joins; LEFT, RIGHT, OUTER, INNER
Copy data from one table to another based on SELECT and WHERE criteria
Input welcomed & appreciated.
Chris
I recommend that you start by following some tutorials on this topic. Your questions are not uncommon questions for someone moving from a beginner to intermediate level in SQL. SQLZoo is an excellent resource for learning SQL so consider following that.
In response to your questions:
1) Find all records with a duplicate in a particular column
There are two steps here: find duplicate records and select those records. To find the duplicate records you should be doing something along the lines of:
select possible_duplicate_field, count(*)
from table
group by possible_duplicate_field
having count(*) > 1
What we're doing here is selecting everything from a table, then grouping it by the field we want to check for duplicates. The count function then gives me a count of the number of items within that group. The HAVING clause indicates that we want to filter AFTER the grouping to only show the groups which have more than one entry.
This is all fine in itself but it doesn't give you the actual records that have those values on them. If you knew the duplicate values then you'd write this:
select * from table where possible_duplicate_field = 'known_duplicate_value'
We can use the SELECT within a select to get a list of the matches:
select *
from table
where possible_duplicate_field in (
select possible_duplicate_field
from table
group by possible_duplicate_field
having count(*) > 1
)
2) SUM price from a linked table within the same query
This is a simple JOIN between two tables with a SUM of the two:
select sum(tableA.X + tableB.Y)
from tableA
join tableB on tableA.keyA = tableB.keyB
What you're doing here is joining two tables together where those two tables are linked by a key field. In this case, this is a natural join which operates as you would expect (i.e. get me everything from the left table which has a matching record in the right table).
3) Explain the difference between the 4 joins; LEFT, RIGHT, OUTER, INNER
Consider two tables A and B. The concept of "LEFT" and "RIGHT" in this case are slightly clearer if you read your SQL from left to right. So, when I say:
select x from A join B ...
The left table is "A" and the right table is "B". Now, when you explicitly say "LEFT" the SQL statement you are declaring which of the two tables you are joining is the primary table. What I mean by this is: Which table do I scan through first? Incidentally, if you omit the LEFT or RIGHT, then SQL implicitly uses LEFT.
For INNER and OUTER you are declaring what to do when matches don't exist in one of the tables. INNER declares that you want everything in the primary table (as declared using LEFT or RIGHT) where there is a matching record in the secondary table. Hence, if the primary table contains keys "X", "Y" and "Z", and the secondary table contains keys "X" and "Z", then an INNER will only return "X" and "Z" records from the two tables.
When OUTER is used, we're saying: Give me everything from the primary table and anything that matches from the secondary table. Hence, in the previous example, we'd get "X", "Y" and "Z" records in the output record set. However, there would be NULLs in the fields which should have come from the secondary table for key value "Y" as it doesn't exist in the secondary table.
4) Copy data from one table to another based on SELECT and WHERE criteria
This is pretty trivial and I'm surprised you've never encountered it. It's a simple nested SELECT in an INSERT statement (this may not be supported by your database - if not, try the next option):
insert into new_table select * from old_table where x = y
This assumes the tables have the same structure. If you have different structures then you'll need to specify the columns:
insert into new_table (list, of, fields)
select list, of, fields from old_table where x = y
Let's say you have 2 tables named :
[OrderLine] with the columns [Id, OrderId, ProductId, Qty, Status]
[Product] with [Id, Name, Price]
1) all orderline of command having more than 1 line (it's technically the same as looking for duplicates on OrderId :) :
select OrderId, count(*)
from OrderLine
group by OrderId
having count(*) > 1
2) total price for all order line of the order 1000
select sum(p.Price * ol.Qty) as Price
from OrderLine ol
inner join Product p on ol.ProductId = p.Id
where ol.OrderId = 1000
3) difference between joins:
a inner join b => take all a that has a match with b. if b is not found, a will be not be returned
a left join b => take all a, match them with b, include a even if b is not found
a righ join b => b left join a
a outer join b => (a left join b) union ( a right join b)
4) copy order lines to a history table :
insert into OrderLinesHistory
(CopiedOn, OrderLineId, OrderId, ProductId, Qty)
select
getDate(), Id, OrderId, ProductId, Qty
from
OrderLine
where
status = 'Closed'
To answer #4 and to perhaps show at least some understanding of SQL and the fact this isn't HW, just me trying to learn best practise;
SET NOCOUNT ON;
DECLARE #rc int
if #what = 1
BEGIN
select id from color_mapper where product = #productid and color = #colorid;
select #rc = ##rowcount
if #rc = 0
BEGIN
exec doSavingSPROC #colorid, #productid;
END
END
END