Join logic between tables without an obvious join condition - sql

I've got 2 tables, one with an area, actions and quantities, and the other with prices and the goal is to combine the two in a view
table1
areaid integer
bananaunits integer
kilometers_ran integer
dogecoins integer
areaid | bananaunits | kilometers_ran | dogecoin
1 | 0 | 1 | 10
2 | 4 | 2 | 100
table2
rateid integer
description text
cost_per_unit integer
rateid | description | cost_per_unit
1 | price per banana | 0.5
2 | price per kilometers run | 2
3 | price per doge | 1
The intended outcome is to have a view which has the fields as following:
areaid, rateid, description, cost_per_unit, units, combined_cost
areaid| rateid| description| cost_per_unit| units| total_cost
1 | 1 | price per banana | 0.5 | 0 | 0
1 | 2 | per kilometers run | 2 | 1 | 2
1 | 3 | price per doge | 1 | 10 | 10
2 | 1 | price per banana | 0.5 | 4 | 2
2 | 2 | per kilometers run | 2 | 2 | 4
2 | 3 | price per doge | 1 | 100 | 100
In other words, I need to present all the rates per area in individual rows. how to achieve this?
Edit: current query that doesnt work
select areaid, rateid, description, cost_per_unit, units, combined_cost from table1,table2

Since you don't have a joining key and you want a row for each of combination of the area and rates, you're basically looking for a CROSS JOIN also called cartesian product

Related

count total items, sold items (in another table reference by id) and grouped by serial number

I have a table of items in the shop, an item may have different entries with same serial number (sn) (but different ids) if the same item was bought again later on with different price (price here is how much did a single item cost the shop)
id | sn | amount | price
----+------+--------+-------
1 | AP01 | 100 | 7
2 | AP01 | 50 | 8
3 | X2P0 | 200 | 12
4 | X2P0 | 30 | 18
5 | STT0 | 20 | 20
6 | PLX1 | 200 | 10
and a table of transactions
id | item_id | price
----+---------+-------
1 | 1 | 10
2 | 1 | 9
3 | 1 | 10
4 | 2 | 11
5 | 3 | 15
6 | 3 | 15
7 | 3 | 15
8 | 4 | 18
9 | 5 | 22
10 | 5 | 22
11 | 5 | 22
12 | 5 | 22
and transaction.item_id references items(id)
I want to group items by serial number (sn), get their sum(amount) and avg(price), and join it with a sold column that counts number of transactions with referenced id
I did the first with
select i.sn, sum(i.amount), avg(i.price) from items i group by i.sn;
sn | sum | avg
------+-----+---------------------
STT0 | 20 | 20.0000000000000000
PLX1 | 200 | 10.0000000000000000
AP01 | 150 | 7.5000000000000000
X2P0 | 230 | 15.0000000000000000
Then when I tried to join it with transactions I got strange results
select i.sn, sum(i.amount), avg(i.price) avg_cost, count(t.item_id) sold, sum(t.price) profit from items i left join transactions t on (i.id=t.item_id) group by i.sn;
sn | sum | avg_cost | sold | profit
------+-----+---------------------+------+--------
STT0 | 80 | 20.0000000000000000 | 4 | 88
PLX1 | 200 | 10.0000000000000000 | 0 | (null)
AP01 | 350 | 7.2500000000000000 | 4 | 40
X2P0 | 630 | 13.5000000000000000 | 4 | 63
As you can see, only the sold and profit columns show correct results, the sum and avg show different results than the expected
I can't separate the statements because I am not sure how can I add the count to the sn group which has the item_id as its id?
select
j.sn,
j.sum,
j.avg,
count(item_id)
from (
select
i.sn,
sum(i.amount),
avg(i.price)
from items i
group by i.sn
) j
left join transactions t
on (j.id???=t.item_id);
There are multiple matches in both tables, so the join multiplies the rows (and eventually produces wron results). I would recommend pre-joining, then aggregating:
select
sn,
sum(amount) total_amount,
avg(price) avg_price,
sum(no_transactions) no_transactions
from (
select
i.*,
(
select count(*)
from transactions t
where t.item_id = i.id
) no_transactions
from items i
) t
group by sn

Trying to join a table of individuals to a table of couples, give a family ID and not time out the server

I have one table with fake individual tax records like so (one row per filer):
T1:
+-------+---------+---------+
| Person| Spouse | Income |
+-------+---------+---------+
| 1 | 2 | 34000 |
| 2 | 1 | 10000 |
| 3 | NULL | 97000 |
| 4 | 6 | 11000 |
| 5 | NULL | 25000 |
| 6 | 4 | 100000 |
+-------+---------+---------+
I have a second table which has tax 'families', a single individual or married couple (one line per tax 'family').
T1_Family:
+-------- -+-------+---------+
| Family_id| Person| Spouse |
+-------- -+-------+---------+
| 2 | 2 | 1 |
| 3 | 3 | NULL |
| 5 | 5 | NULL |
| 6 | 6 | 4 |
+------ ---+-------+---------+
Family = max(Person) within a couple
The idea of joining the two is for example, to sum the income of 2 people in one tax family (aggregate to the family level).
So, I've tried the following:
select *
into family_table
from
(
(select * from T1_family)a
join
(select * from T1)b
on a.family = b.person **or a.spouse = b.person**
)
where family_id is not null and person is not null
What I should get (and I do get when I select 1 random couple) is one line per individual where I can then group by family_id and sum income, pension contributions, etc. BUT SQL times out before the tables can be joined. The part in bold is what's slowing down the process but I'm not sure what else to do.
Is there an easier way to group by family?
It is simpler to put the data on one row:
select a.*, p.income as person_income, s.income as spouse_income
into family_table
from t1_family a left join
t1 p
on a.person = p.person lef tjoin
t1 s
on a.spouse = s.person;
Of course, you can add them together as well.

SQL - SELECT all households by last value

I'm facing a problem that I cant wrap my head around so maybe you can help me to solve it!?
I have one table:
id | datetime | property | house_id | household_id | plug_id | value
---+--------------------+----------+----------+--------------+---------+--------
1 |2013-08-31 22:00:01 | 0 | 1 | 1 | 1 | 15
2 |2013-08-31 22:00:01 | 0 | 1 | 1 | 3 | 3
3 |2013-08-31 22:00:01 | 0 | 1 | 2 | 1 | 21
4 |2013-08-31 22:00:01 | 0 | 1 | 2 | 2 | 1
5 |2013-08-31 22:00:01 | 0 | 2 | 1 | 3 | 53
6 |2013-08-31 22:00:02 | 0 | 2 | 2 | 4 | 34
7 |2013-08-31 22:00:02 | 0 | 1 | 1 | 1 | 16
...
The table holds electricity consumption measurements per second for multiple houses that have multiple households (apartments) in them. Each household has multiple electricity plugs. None of the houses or households have a unique id but are identified by a combination of house_id and household_id.
1) I need a SQL query that can give me a list of all the unique households.
2) I want to use the list from 1) to create a SQL query that gives me a list of the highest value for each household (the value is cumulative, so the latest datetime holds the highest value). I need a total value (SUM) for each household (sum of all the plugs in that household), i.e. a list of of households with their total electricity consumption.
Is this even possible? I'm using SQL Server 2012 and the table has 100.000.000 rows.
If I understand correctly, you want the sum of the highest values of value, for house/household/plug combinations. This may do what you want:
select house_id, household_id, sum(maxvalue)
from (select house_id, household_id, plug_id, max(value) as maxvalue
from consumption
group by house_id, household_id, plug_id
) c
group by house_id, household_id;
according to your description I think you can use this query;
select house_id,household_id, max(value), sum(value) from your_table_name group by house_id,household_id

Can't figure out a simple SQL query

Might be very simple, but I've been digging fow a few days now... I just can't figure out how to make this SQL query in Access...
In reference to the tables below, i'm looking for the query that can extract all the ITEMS for a specific Shop (ie 1:Alpha) from a specific GROUP (ie 1:Tools), that are NOT in the report for 2014... in this case ITEMS.IDs 6, 8, 9 and 10!
Tables:
Years
ID | Year
-----------------------------------------------
1 | 2014
2 | 2015
Shops
ID | ShopName
-----------------------------------------------
1 | Alpha
2 | Bravo
Items
ID | StockNbr | Description | GroupID
-----------------------------------------------
1 | 00-1200 | Ratchet 1/4 | 1
2 | 00-1201 | Ratchet 1/2 | 1
3 | 00-1300 | Screwdriver Philips No1 | 1
4 | 01-5544 | Banana | 2
5 | 00-4457 | Apple | 2
6 | 21-8887 | Hammer | 1
7 | 21-6585 | Drill | 1
8 | 21-4499 | Multimeter | 1
9 | 21-5687 | Digital Caliper | 1
10 | 22-7319 | File Set | 1
...
Groups
ID | GroupName
-----------------------------------------------
1 | Tools
2 | Fruits
REPORTS
ID | YearID | ShopID | ItemID
-----------------------------------------------
1 | 1 | 1 | 1
2 | 1 | 1 | 2
3 | 1 | 1 | 3
4 | 1 | 1 | 4
5 | 1 | 1 | 7
6 | 1 | 2 | 5
7 | 1 | 2 | 8
8 | 1 | 2 | 10
I've tried this, but then I realize it doesn't take the shops into consideration, it'll list all items that are not listed in reports, so if reports has an item for shop 2, it won't list it either...
SELECT Items.ID, Items.StockNbr, Items.Description, Items.GroupID, Reports.YearID, Reports.ShopID
FROM Reports
RIGHT JOIN Items ON Reports.ItemID = Items.ID
WHERE (((Items.GroupID)=1) AND ((Reports.UnitID) Is Null))
ORDER BY Items.StockNbr;
Thank you!
I think you're looking for an anti-join. There are several ways to do this. Here's one using not in.
select i.* from items i
where i.GroupId = 1
and i.ID NOT IN (
select ItemID from reports r
where r.ShopID = 1
and r.YearID = 2014
)
If the table Reports does not reference Items.ID then there is no available relationship ShopID or YearID
select *
from items
left join reports on items.id = reports.itemid
where reports.itemid IS NULL

SQL: Transfer from column to row, size systems, fashion

I'm struggling, hope you can help me out! The application is an ERP system in MS ACCESS for fashion retailing.
The question: How can I add a row in Table3 with the article's corresponding SizeID1, SizeID2 etc filled according to it's size system of Table2?
Table1: Article details containing size system
ArticleID | SizeType
--------------------
1 | US
2 | EU
Table2: Different size systems for different regions
SizeID | Size | SizeType
------------------------
1 | S | US
2 | M | US
3 | L | US
4 | XL | US
5 | 36 | EU
6 | 38 | EU
7 | 40 | EU
Table3: Order details
OrderID | ArticleID | Size1 | Amount1 | Size2 | Amount2 | Size3 | Amount3
-------------------------------------------------------------------------
1 | 1 | S | 1 | M | 3 | L | 1
2 | 2 | 36 | 2 | 38 | 1 | 40 | 3
3 | 2 | 36 | | 38 | | 40 |
The row with OrderID = 3 is the goal of the insery query for ArticleID 2. I can then enter the amount to the corresponding size. Thanks for your help!!
It's not entirely clear what you're trying to achieve here, but I think that might be because your database design is a bit broken.
You're probably used to working with spreadsheets, becase you seem to have designed your Table3 as if it were a spreadsheet. Any time you end up with repeating fields in a database table (eg. Size1, Size2, Size3....) then it's a sign that you need to normalise more.
Please read up on database normalisation: http://www.studytonight.com/dbms/database-normalization.php (and also google generally for database normalisation for more info).
I suspect you'll need something more like this:
Article table:
ArticleID | ArticleName | SizeType(FK to SizeType table)
1 | Blue T-shirt | 1
2 | Red T-shirt | 2
SizeType table:
SizeTypeID | SizeTypeDescription
1 | US
2 | EU
Sizes table:
SizeID | SizeType(FK) | SizeDescription
1 | 1 | 38
2 | 1 | 40
3 | 2 | M
4 | 2 | L
Items table:
ItemID | ArticleID(FK) | SizeID(FK)
1 | 1 | 1 'Blue T-shirt size 38
2 | 1 | 2 'Blue T-shirt size 40
3 | 2 | 3 'Red T-shirt size M
4 | 2 | 4 'Red T-shirt size L
Orders table:
OrderID | CustomerID (FK) | OrderDate | etc. (other info you need to store about an order)
1 | 2458 | 01/01/2001|
2 | 3452 | 02/02/2002|
Order Details table:
OrderDetailsID | OrderID(FK) | ItemID (FK) | Quantity
1 | 1 | 3 | 6
2 | 1 | 4 | 3
3 | 2 | 1 | 1
So here linking everything back, Customer with ID 2458 has ordered 6x Size M Red T-shirts and 3x Size L Red T-shirts, and Customer with ID 3452 has ordered 1x size 38 Blue T-shirt.
Note You'd also realistically have a PRICE field in either the Items table (if the price varies with the size of an item) or in the Article table (if the price is the same for every size). CustomerID would also link back to a table containing a customer's details (Name, address, username/password etc).
You might also have other things that I've not shown here, for example in either your Articles table or your Items table you'll probably have a supplierID which tells you who you buy that item from, as well as a supplierItemNo which would be a unique code (barcode?) which you use to order that item.
Once your database is structured properly it will be much easier to write queries to insert records etc.