Sum values from different tables - sql

I read some topics about this but I'm not very good with sql. I have 10 tables with these fields:
value
type
date
I want to sum all the value fileds together when they have a specific type. I was trying to do something like this, but it's not working.
select sum(tab1.value) + sum(tab2.value)
from tab1, tab2
where tab1.type = tab2.type = 'box'
I guess I could do many simple queries like these and then sum all the results
select sum(value) from tab1 where type='box'
select sum(value) from tab2 where type='box'
but I wonder if I can do one single query
thanks

Having multiple tables with the same structure is usually a sign of poor database design.
I would suggest that you use your last approach, but put the subqueries in the from clause and then add the results in the select:
select t1.value + t2.value + . .
from (select sum(value) as value from tab1 where type='box') t1 cross join
(select sum(value) as value from tab2 where type='box') t2 cross join
. . .
Alternatively, you could union all them together in the from clause and then take the sum:
select sum(value)
from ((select sum(value) as value from tab1 where type='box') union all
(select sum(value) as value from tab2 where type='box') union all
. . .
) t;

If the tables are not linked via FK/PK you can use multiple sub-queries:
SELECT (SELECT SUM(tab1.value) FROM tab1 WHERE type='box') as Tab1Sum,
(SELECT SUM(tab2.value) FROM tab2 WHERE type='box') as Tab2Sum -- and so on...
This yields a single record where each column is the sum of each table.

1.Use single select;
DECLARE #type NVARCHAR(255) = N'Box';
SELECT (SELECT SUM(value) FROM tab1 WHERE type=#Box)
+ (SELECT SUM(value) FROM tab2 WHERE type=#Box)
+ (SELECT SUM(value) FROM tab3 WHERE type=#Box)
+ (...)
I think it's simplest one.
2.you create a view as
CREATE VIEW tabs
AS
SELECT value, type FROM tab1
UNION
SELECT value, type FROM tab2
UNION
SELECT value, type FROM tab3
UNION
...
Then
SELECT SUM(value) FROM tabs WHERE type = 'BOX'
3.Think why similar column are different tables. Can they be merged into single table?
If answer is No, and you have too many tables, consider concatenate SQL strings and use sp_executesql to execute it.

Related

Select count(*) from table where (multiple id) in (table)

Is there a way to write
SELECT count(*) from tablename where (multiple_ids_here) in (SELECT id from tablename)
Normally, I would write:
select count(*) from tablename
where id_1 in (SELECT id from tablename)
OR id_2 in (SELECT id from tablename)
id_3 in (SELECT id from tablename)
which very inefficient if we have multiple values.
Anyone?
EDIT: Question updated. What if I want to select count?
Your version with three ins is probably the most efficient way of doing this. If you want a comparison to try, you can use exists:
select . . .
from t t1
where exists (select 1
from tablename t2
where t2.id in (t1.id_1, t1.id_2, t1.id_3)
);
I should also note that storing ids in multiple columns like this is usually a sign of a problem with the data model. You probably want a table with one row per id, rather than one column per id. Such a format would also simplify this type of query.
For the updated question regarding getting a count(*)... using cross apply() with values() to unpivot your data in a common table expression:
;with cte as (
select t.Id, v.RelatedId
from t
cross apply (values (id_1),(id_2),(id_3)) v(RelatedId)
)
select
cte.Id
, RelationCount = count(*)
from cte
inner join RelatedTable r
on cte.RelatedId = r.Id
group by cte.Id
I am not sure i understand your question could you give an example of the data you are using and the out come.
From what i understand you could use a cte like this .
;WITH Sales_CTE ([counts],CustomerID, SalespersonPersonID,PickedByPersonID)
AS
(
select count(*),CustomerID,SalespersonPersonID ,PickedByPersonID
from [WideWorldImporters].[Sales].[Orders]
group by CustomerID,SalespersonPersonID,PickedByPersonID
)
SELECT sum([counts])
FROM Sales_CTE
GO
It would give you a result like this . You would jsut have to change the columns around .

sql query return the rows without common attributes

I'm new with sql ans ms-access.
So, i have table tab1, with columns
id, decscription, number
i want to make a query that returns the id of the rows without common description and number.
The desirable output is this
I have tried
SELECT id
FROM tab1
GROUP BY id, description, Number HAVING COUNT(*)=1;
but returns logical error.
If you want to return rows that are unique, you can do:
select *
from tab1
where not exists (select 1
from tab1 as t
where tab1.description = t.description and tab1.number = t.number and
tab1.id <> t.id
);
You can also do this using aggregation. To get the id:
select max(id)
from tab1
group by description, number
having min(id) = max(id);
SELECT id
FROM tab1
GROUP BY description, Number HAVING COUNT(*)=1;
Your question isn't quite clear, perhaps:
SELECT
id, description, Count(*) As Number
FROM
tab1
GROUP BY
id, description

I need help combining a few select statements

I would like to pull all of the columns from my second select statement and put it to the right of all of my columns from my first statement.
I have tried Union and the join commands with no luck.
When I use these they just have what I wanted from my first select statement.
Here is basic code I have.
Select * from MTG_TREND where LINEID='A2' end;
Select * from MTG_TREND where LINEID='B2'
All of the other columns are the same.
Select t1.*,t2.* from MTG_TREND t1
left join (
Select * from MTG_TREND where LINEID='B2'
) as t2
on t1.primarykey=t2.primarykey
where t1.LINEID='A2'
NOTE:
- Make sure you are matching the same number of columns in both SELECT Statement.
- Another thing to remember is you have to have the same matched column (datatype).
- If there are some columns that are not present is the table then just defined the column with null so that you can get it in output from another select statement.
Select col1, col2, col3,...... from MTG_TREND where LINEID='A2'
UNION ALL
Select col1, col2, col3,...... from MTG_TREND where LINEID='B2'

MS SQL Server sum of sum fields

I have a sql statement that will give me two columns from two tables using sub query.
select
sum(field1) as f1_sum,
(select sum(field2) from table2) as f2_sum
from
table1
group by
table1.field_x
I want to get the total of f1_sum + f2_sum as the third column output from this query. It seems simple but I can't find a way around this.Question is how to get the sum of sum fields.
I am ok to write SP or a view to do this etc..
Can someone assist please ?
you can use subquery like:
SELECT t1.f1_sum+t1.f2_sum AS total_sum FROM
(select sum(field1) as f1_sum , (select sum(field2) from table2) as f2_sum
from table1
group by table1.field_x) AS t1
I would suggest doing it like this:
select t1.f1_sum, t2.f2_sum, coalesce(t1.f1_sum, 0) + coalesce(t2.f2_sum, 0)
from (select sum(field1) as f1_sum
from table1 t1
group by t1.field_x
) t1 cross join
(select sum(field2) as f2_sum from table2) t2;
When possible, I prefer to keep table references in the from clause. I added the coalesce() just in case any of the values could be NULL.
You could also try this :
SELECT SUM(a.field1) f1_sum,
SUM(b.field2) f2_sum,
(SUM(a.field1) + SUM(b.field2)) f3_sum
from table1 a, table2 b
Simply you can write,
select sum(field1) as f1_sum
, (select sum(field2) from table2) as f2_sum
, (ISNULL(sum(field1),0) + ISNULL((select sum(field2) from table2),0)) AS Total_Sum
from table1
group by table1.field_x

Union with no duplicate only for first column

I am using the UNION syntax to retrieve a product code and description from several databases.
I want to retrieve only a unique product code, even if this product code has several descriptions. I want to retreive only the first result.
To do that, I am using this script:
SELECT * FROM (SELECT tab1.code, tab1.description FROM tab1
UNION
SELECT tab2.code, tab2.description FROM tab2
UNION
SELECT tab3.code, tab3.description FROM tab3)
Unfortunately, this script will retrieve several product codes if the specific product has more than one description.
How can this be modified to retrieve only the first occurrence with a description?
If you want ANY one description, you can go with max or min like this:
select code, max(description) from (your set of unions)
group by code
In this case, you can change UNION to UNION ALL to skip on sorting.
If you really want the first one, you would need to indicate it:
select code, description from (
select code, description, ord, min(ord) over (partition by code) min_ord from (
select code, description, 1 as ord from table1
union all
select code, description, 2 as ord from table2
union all
select code, description, 3 as ord from table3
)
) where ord = min_ord
I think that this solution works but maybe it is not elegant.
SELECT * FROM
(
SELECT tab1.code, tab1.description FROM tab1
UNION
SELECT tab2.code, tab2.description FROM tab2 WHERE tab2.code not in
(SELECT tab1.code FROM tab1)
UNION
SELECT tab3.code, tab3.description FROM tab3 WHERE tab3.code not in
(SELECT tab1.code FROM tab1
UNION
SELECT tab2.code FROM tab2)
)
Your query might be more efficient with a full outer join, if there are no duplicates within a table and description does not take on NULL values:
SELECT coalesce(tab1.code, tab2.code, tab3.code) as code,
coalesce(tab1.description, tab2.description, tab3.description) as description
FROM tab1 full outer join
tab2
on tab2.code = tab1.code full outer join
tab3
on tab3.code = coalesce(tab1.code, tab2.code);
This saves the duplicate elimination step (or aggregation) and allows better use of indexes.