Multiple table joins with aggregate (mssql / sql server) - sql

Very simple question. What I want to do is select all columns from one table and sum of one column (which could have multiple matching rows) from another table.
Example:
table ta (eid, uid, name, year, etc, etc, etc)
table tb (eid, uid, name, year, amount, etc, etc)
eid - will not match between both table
uid, name, year - will match across both tables
So I want to pull out all columns from table ta, simple:
select * from ta where eid='value';
I want to join amount column from table tb to my resultset, simple:
select a.*, b.amount
from ta a
inner join tb b on a.year=b.year
where a.eid='value';
Great, this works fine. But what if I have multiple rows in table tb?
Executing:
select a.*, sum(b.amount)
from ta a inner join tb b on a.uid=b.uid
where a.year='value';
gives me the following error:
Column 'ta.eid' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
So I add:
select a.*, sum(b.amount)
from ta a inner join tb b on a.uid=b.uid
where a.year='value' group by ta.uid;
And I get the same error!
However, if I change my query to:
select a.uid, a.year, sum(b.amount)
from ta a inner join tb b on a.uid=b.uid
where a.year='value'
group by ta.uid, ta.year;
It works, but now I have three columns instead of all columns that I wanted.
So, at this point my question becomes: Is there a better, cleaner way of structuring this query other than me manually typing out all columns I want to pull from two tables with GROUP BY clause?

You can preaggregate in a subquery:
select a.*, b.sumb
from ta a left join
(select b.uid, sum(b.amount) as sumb
from tb b
group by b.uid
) b
on a.uid=b.uid
where a.year = 'value';

Related

SQL - select * given count from another table

I'm trying to select * from two tables (a and b) using a join (column a.id and b.id), given that the count of a column (b.owner) in b is lower than 3, i.e. the occurence of a person's name can be max 2.
I've tried:
SELECT a.*, COUNT(b.owner) AS b_count
FROM a LEFT JOIN b on a.id = b.id
GROUP BY b.owner HAVING COUNT(b_count) <3
As im pretty new to SQL, im pretty stuck here. How can i resolve this issue? The result should be all columns for owners who do not appear more than twice in the data.
The query you are trying to run is not working due to the columns missing in the GROUP BY clause.
As you are outputting all columns from table a (with SELECT a.*), you need to include all those columns in the GROUP BY statement, so that the database understand the group of fields to group by and perform the aggregation required (in your case COUNT(b.owner)).
Example
Considering that your table a has 3 columns below:
CREATE TABLE persons (
id INTEGER,
name VARCHAR(50),
birthday DATE,
PRIMARY KEY (id)
);
.. and your table b the following and referencing the first table as below:
CREATE TABLE sales (
id INTEGER,
person_id INTEGER,
sale_value DECIMAL,
PRIMARY KEY (id),
FOREIGN KEY (person_id) REFERENCES persons(id)
);
.. you should query it aggregating the COUNT() by those 3 columns:
SELECT a.id, a.name, a.birthday, COUNT(b.person_id) AS b_count
FROM persons a
LEFT JOIN sales b ON a.id = b.person_id
GROUP BY a.id, a.name, a.birthday
HAVING COUNT(b.person_id) < 3
Alternative
In case the total of records on the 2nd table is not important to you, you could use a different "strategy" here to avoid performing the JOIN between the tables (useful when joining two huge tables) and rewriting all the columns from a on the SELECT+GROUP BY.
By identifying the records that has less than the 3 occurrences firstly:
SELECT b.person_id
FROM sales b
GROUP BY b.person_id
HAVING COUNT(b.id) < 3;
.. and using it in the WHERE clause to retrieve all the columns from the 1st table only for the ids that resulted from the previous query:
SELECT a.*
FROM persons a
WHERE a.id IN (....other query here....);
.. the execution happens in a more chronological and, perhaps, easier way to visualize while getting more familiar with SQL:
SELECT a.*
FROM persons a
WHERE a.id IN (SELECT b.person_id
FROM sales b
GROUP BY b.person_id
HAVING COUNT(b.id) < 3);
DB Fiddle here
In Standard SQL, you can use:
SELECT a.*, COUNT(b.owner) AS b_count
FROM a LEFT JOIN
b
ON a.id = b.id
GROUP BY a.id
HAVING COUNT(b.owner) < 3;
This may not work in all databases (and it assumes that a.id is unique/primary key). An alternative would be to use a correlated subquery:
SELECT a.*
FROM (SELECT a.*,
(SELECT COUNT(*)
FROM b
WHERE a.id = b.id
) as b_count
FROM a
) a
WHERE b_count < 3;

Getting column names of a query in Teradata

I'm trying to get only columns names of a query result without the need of running all the query.
for example, if table a columns are: id, price, txn_date,city_id and table b columns are: city_id,city_name, country
I want a query that will output only column names of the following query:
Select a.*,b.* from a left join b on a.city_id=b.city_id
without using CPU to compute all the results.
desired output:
id, price, txn_date, city_id, city_name, country
try add condiniion ever false and use an inner join
Select a.*,b.* from a inner join b on a.city_id=b.city_id and 1= 2
this should return a result without rows
or dorectly
Select a.*,b.* from a inner join b on 1= 2

SQL Server query for calculating sum

I am trying to write a SQL query for calculating sum without success.
Let's say that we have:
table A with columns id and type
table B with columns id, a_id (relation to table A) and amount
I succeed to calculate number of records by type like in the following example:
SELECT DISTINCT
type,
COUNT(A.id) OVER (PARTITION BY type) AS numOfRecords
FROM A;
How to calculate sum of amounts also per type (to sum up all amounts from table B for all distinct types in A)?
Your query would normally be written as:
select type, count(*) as num_records
from A
group by type;
Then, you can incorporate b as:
select a.type, count(*) as num_records, sum(b.amount)
from A left join
(select a_id, sum(amount) as amount
from b
group by a_id
) b
on b.a_id = a.id
group by a.type;
You can also join and aggregate without a subquery, but this will throw off the count. To fix that, you can use count(distinct):
select a.type, count(distinct a.id) as num_records, sum(b.amount)
from A left join
from b
on b.a_id = a.id
group by a.type;

how to define table name and conduct multiple table selection

I need to use multiple table selections in a query in SQL. But how to reference a table selected within a query?
for example: (pseudo code)
create table C as
select distinct id, product_code
from (
select distinct id, product_code
from A where dt = '2019-06-01'
)
inner join B on (select distinct id, product_code
from A where dt='2019-06-01').id = B.id;
the code above might be wrong, but the point is that the table A could not be used directly since it's too large and it has to be specified that dt is some specific value. (so I need to select something from A for double times above). And I need to inner join the smaller A' with some other table B.
Is it possible, say, "define" that table A_ = select distinct blabla...from A ... and then join A_ with B within a query?
thanks,
You just want a table alias:
select distinct id, product_code
from (select distinct id, product_code
from table_A
where dt = '2019-06-01'
) a inner join
table_B b
on a.id = B.id;

Join two tables and retrieve relevant data and calculate the result

We have two tables table1 and table2
Table 1
Table 2
We need the resultant table as :
All this should be done in a single SQL query
Thanks in advance.
I think you can make it without the second query, I tested it and returned your expected values.
select table_2.id_pro,
product_name,
SUM(1) as Quantity,
priceprod,
SUM(1) * priceprod as 'quantity * priceprod'
from Table_2
inner join Table_1 t1 on table_2.id_pro = t1.id_pro
group by table_2.id_pro, product_name, priceprod
And my SqlFiddle test http://sqlfiddle.com/#!3/08c2ef/1
I believe this should be what you need, or fairly close anyway! You need to group up your results from your first table to get your quantity value and then join those results to your second table to be able to create your desired output.
SELECT t1.id_pro,
t2.product_name,
s.Quantity,
t2.priceperprod,
s.Quantity * t2.priceperprod
FROM table_2 t2
INNER JOIN (
SELECT COUNT(*) AS Quantity,
t.id_pro
FROM table_1 t
GROUP BY t.id_pro
) t1 ON t2.id_pro = t1.id_pro
i believe that this is correct, i just JOIN the two tables AND used group by then count how many records each group, i hope this will help you, thanks.
SELECT
A.id_pro,
A.product_name,
(count(*)) AS Quantity,
A.priceperprod,
(COUNT(*) * A.priceperprod) AS Total
FROM table_2 A
LEFT JOIN table_1 B
ON B.id_pro = A.id_pro
GROUP BY A.id_pro
Guess this should be helpful to you.
SELECT A.PRODUCT_CODE, A.PRODUCT_NAME, B.QUANTITY,
A.PRICE PRICE_PER_PRODUCT,
(B.QUANTITY * A.PRICE) TOTAL_PRICE FROM
TABLE2 A,
(SELECT X.PRODUCT, COUNT(X.PRODUCT) QUANTITY FROM TABLE1 AS X
GROUP BY X.PRODUCT) as B
WHERE A.PRODUCT_CODE = B.PRODUCT
ORDER BY A.PRODUCT_CODE
Am doing following :
Taking the entire TABLE2 aliased as A
Getting the products and its corresponding count using group by and aliasing it as B
Selecting corresponding fields from table_Aliases A and B provided A's ProductCode and B's Products are same.