mysql query with left outer join and average - mysql

I have two tables in mysql. The first table is names have the following dates:
name service number
carlos telephone 6
juan watter 12
maria gas 23
jhon hostal 17
marcos sleeping 21
carlos othercarlos 12
other other 13
And i have other table alias
name service alias price
carlos telephone telephone-carlos 700
carlos sleeping sleeping-carlos 300
juan watter watter-juan 900
maria gas gas-maria 650
jhon hostal hostal-jhon 700
And i need a view with name, alias, number and prince.
But i need all rows in name i intent with a left outer join.
But the problem is that when i do the query when is othercarlos i need that the price will be the average of carlos services and when the name is other i need that appear the average of all services. But appear null
http://sqlfiddle.com/#!2/c1d4f/1
I create this tables and my query

Ok, I'm sure that there are better ways to do this, but I can at least offer you one way:
SELECT t1.name,
t1.service,
t2.alias,
t1.number,
COALESCE(t2.price,t3.price,t4.price) AS price
FROM name t1
LEFT JOIN alias t2
ON t1.name= t2.name
AND t1.service = t2.service
LEFT JOIN ( SELECT name, AVG(price) AS price
FROM alias
GROUP BY name) t3
ON t1.name = t3.name
LEFT JOIN ( SELECT AVG(price) AS price
FROM alias) t4
ON t1.name = 'other'
Here is a fiddle with this.
The result:
╔════════╦═════════════╦══════════════════╦════════╦═══════╗
║ NAME ║ SERVICE ║ ALIAS ║ NUMBER ║ PRICE ║
╠════════╬═════════════╬══════════════════╬════════╬═══════╣
║ carlos ║ telephone ║ telephone-carlos ║ 6 ║ 700 ║
║ juan ║ watter ║ watter-juan ║ 12 ║ 900 ║
║ maria ║ gas ║ gas-maria ║ 15 ║ 250 ║
║ jhon ║ hostal ║ hostal-jhon ║ 21 ║ 640 ║
║ carlos ║ sleeping ║ sleeping-carlos ║ 24 ║ 300 ║
║ carlos ║ othercarlos ║ (null) ║ 11 ║ 500 ║
║ other ║ (null) ║ (null) ║ 2 ║ 558 ║
╚════════╩═════════════╩══════════════════╩════════╩═══════╝

Related

Get oldest timestamp from each user_id

Database of "sales"
Each "sold_by" is the person who essentially has made that particular sale. My aim is to get the most recent "sale_date" grouped by "sold_by" to return one record for each unique "sold_by" record (which is stored as an integer in my database, but this is an example)
╔═════════╦═════════╦══════════════════╗
║ sale_id ║ sold_by ║ sale_date ║
╠═════════╬═════════╬══════════════════╣
║ 0 ║ PETER ║ 01/01/2017 00:00 ║
║ 1 ║ JOHN ║ 01/01/2017 00:00 ║
║ 2 ║ PETER ║ 30/03/2017 00:00 ║
║ 3 ║ JOHN ║ 03/02/2017 00:00 ║
║ 4 ║ SIMON ║ 04/02/2017 00:00 ║
║ 5 ║ JOHN ║ 05/01/2017 00:00 ║
║ 6 ║ SIMON ║ 26/01/2017 00:00 ║
║ 7 ║ PETER ║ 07/01/2017 00:00 ║
║ 8 ║ SIMON ║ 28/01/2017 00:00 ║
║ 9 ║ JOHN ║ 09/01/2017 00:00 ║
║ 0 ║ PETER ║ 20/01/2017 00:00 ║
╚═════════╩═════════╩══════════════════╝
Database example for account_manager_sellers (please note, the ID matches sold_by in the table above.
╔════╦══════════════╗
║ id ║ company_name ║
╠════╬══════════════╣
║ 0 ║ PETER ║
║ 1 ║ JOHN ║
║ 2 ║ SIMON ║
╚════╩══════════════╝
The example below works but is not working as desired, it is not getting MIN or MAX date but seemingly returning a random date from the middle of the database.
SELECT `sold_by`, `sale_date`
FROM `sales`
NATURAL JOIN (
SELECT `sold_by`, MAX(`sale_date`) AS entry_date
FROM `sales`
GROUP BY `sold_by`
) AS tmin
JOIN `account_manager_sellers` USING (`id`)
WHERE `sale_date` < '2017-03-31 00:00:00';
So ultimately, I need to get ONE record for each unique sold_by but it needs to be the most recent date. So from the first table above it would return:
+---+-------+------------------+
| 2 | PETER | 30/03/2017 00:00 |
+---+-------+------------------+
| 3 | JOHN | 03/02/2017 00:00 |
+---+-------+------------------+
| 4 | SIMON | 04/02/2017 00:00 |
+---+-------+------------------+
P.S I also tried removing the MAX(sale_date) from the sub query, and replacing that with an ORDER BY sale_date LIMIT 1 (but obviously it only returned one sole result)
The basic query you want might look something like this:
SELECT p1.*
FROM plans p1
INNER JOIN
(
SELECT seller_id, MAX(plan_written) AS entry_date
FROM plans
GROUP BY seller_id
) p2
ON p1.seller_id = p2.seller_id AND
p1.plan_written = p2.entry_date;
You also have another join to the account_manager_sellers table, but since I can't see your table definitions, don't know your columns, etc., I won't attempt an answer for that.
You might want to move away from using natural joins, because they can obfuscate the join conditions in your query.

How to get all items and their value by mysql query

I have three mysql tables.
Table-01: table_item
In this table, all items with their corresponding ids are stored. Items are categorized in two categories. One is writing category (catid-1) and another is clothing category (catid-2).
---------------------------------------------
| id | catname | catid | itemid | itemname |
---------------------------------------------
║ 1 ║ writing ║ 1 ║ 1 ║ Pen ║
║ 2 ║ writing ║ 1 ║ 2 ║ Pencil ║
║ 3 ║ writing ║ 1 ║ 3 ║ Sharpner ║
║ 4 ║clothing ║ 2 ║ 4 ║ Pant ║
║ 5 ║clothing ║ 2 ║ 5 ║ shirt ║
║ 6 ║clothing ║ 2 ║ 6 ║ coat ║
║ 7 ║clothing ║ 2 ║ 7 ║ Tie ║
---------------------------------------------
Table-02: bid_item
Each year bid/tender is called for purchasing selective items from the above item table (table_item). So in this table, selected items, those are selected for bid/tender, are stored per year basis.
----------------------
║ id ║ itemid ║ year ║
----------------------
║ 1 ║ 1 ║ 2015 ║
║ 2 ║ 2 ║ 2015 ║
║ 3 ║ 3 ║ 2015 ║
║ 4 ║ 4 ║ 2015 ║
║ 5 ║ 5 ║ 2015 ║
║ 6 ║ 6 ║ 2015 ║
║ 7 ║ 1 ║ 2016 ║
║ 8 ║ 2 ║ 2016 ║
║ 9 ║ 3 ║ 2016 ║
║ 10 ║ 4 ║ 2016 ║
║ 11 ║ 7 ║ 2016 ║
----------------------
Table-03: bid_2015
After calling bid/Tender, rate of the corresponding companies for selected items are stored in this table. Each company will not give bid price for each items selected for a particular year. Tables are created according to the year alias. Here bid rate for year 2015 are stored as below:
--------------------------------
║ id ║ itemid ║ company ║ rate ║
--------------------------------
║ 1 ║ 1 ║ X ║ 2.0 ║
║ 2 ║ 2 ║ X ║ 2.2 ║
║ 3 ║ 3 ║ X ║ 1.0 ║
║ 4 ║ 4 ║ X ║ 10.0 ║
║ 5 ║ 5 ║ X ║ 15.0 ║
║ 6 ║ 1 ║ Y ║ 1.5 ║
║ 8 ║ 2 ║ Y ║ 2.0 ║
║ 9 ║ 3 ║ Y ║ 1.5 ║
║ 10 ║ 4 ║ Y ║ 12.0 ║
║ 11 ║ 6 ║ Y ║ 20.0 ║
--------------------------------
I need a html table (with input field) for data entry/edit for a particular year (Here, for 2015). Table will contain following:
1) Table will show each items for clothing catagory (catid-2)those are declared for the bid/tender for 2015.
2) If a company bids price, price will be in rate column, otherwise rate column will be blank. Administrator can either change the price (if entered wrong bid price) or add rate for other items which was not entered at first for a particular table.
So the look of the html table form will be as below:
HTML Form-Table (For Data Entry/Edit) : For Company-Y and clothing catagory for the year-2015
Company: (drop-down menu- Company-Y)
------------------------------------------------------
Item Name | Rate |
----------------------
Pant | 12.0 |
-----------------------
Shirt |
-----------------------
Coat | 20.0 |
-----------------------
============
Submit
============
As you can see Rate of Shirt is blank for Company-Y as this company did not give bid price for Shirt. If this company give the price of Shirt at later, rate can be entered and can update the table.
So what would be mysql query to get a html form table like above?
If I execute this query:
SELECT i.itemname,d.rate FROM table_item as i INNER JOIN bid_item as b ON i.itemid=b.itemid LEFT JOIN bid_2015 as d ON b.itemid=d.itemid WHERE i.catid=2 AND d.company='Y' AND b.year=2015
But the expected html table is not coming. As INNER and LEFT Join are used, Item Names are shown more than once in the form table.
What will be the effective mysql query to output a html form table like above?
this works for all data of company Y in 2015
select itemname,
rate
from table_item join bid_item on(table_item.itemid=bid_item.itemid and year=2015 and catid=2)
left join bid_2015 on( bid_2015.itemid=bid_item.itemid and
bid_item.itemid=table_item.itemid and company='Y' and year=2015 and catid=2)
This query will work fine.
SELECT i.itemname,
d.rate
FROM table_item as i
INNER JOIN bid_item as b ON i.itemid=b.itemid AND b.year=2015
LEFT JOIN bid_2015 as d ON b.itemid=d.itemid AND d.company='Y'
WHERE i.catid=2
Note:
When ever you are making LEFT/RIGHT joins on a table (say b as in
your example below). Never put conditions of table 'b' in WHERE
clause. It will act as INNER JOIN .
So the this code
SELECT i.itemname,
d.rate
FROM table_item as i
INNER JOIN bid_item as b ON i.itemid=b.itemid
LEFT JOIN bid_2015 as d ON b.itemid=d.itemid
WHERE i.catid=2 AND d.company='Y' AND b.year=2015
Act as INNER JOIN as given below.
SELECT i.itemname,
d.rate
FROM table_item as i
INNER JOIN bid_item as b ON i.itemid=b.itemid
INNER JOIN bid_2015 as d ON b.itemid=d.itemid
WHERE i.catid=2 AND d.company='Y' AND b.year=2015
Hope this helps.

MySQL - Merge rows in table based on multiple criteria

I'd like to merge rows based on multiple criteria, essentially removing duplicates where I get to define what "duplicate" means. Here is an example table:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 2 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
║ 5 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
In my example, let's say I want to merge on name and age but ignore grade. The result should be:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
I don't particularly care if the id column is updated to be incremental, but I suppose that would be nice.
Can I do this in MySQL?
My suggestion, based on my above comment.
SELECT distinct name, age, grade
into tempTable
from theTable
This will ignore the IDs and give you only a distinct dump, and into a new table.
Then you can either drop the old and, and rename the new one. Or truncate the old one, and dump this back in.
You could just delete the duplicates in place like this:
delete test
from test
inner join (
select name, age, grade, min(id) as minid, count(*)
from test
group by name, age, grade
having count(*) > 1
) main on test.id = main.minid;
Example: http://sqlfiddle.com/#!9/f1a38/1

How do I write an SQL query where two columns need to be translated?

I've got two tables- one with records of stock, the other with translations (for French and German users).
Stock:
╔════╦═══════╦═══════════════════╦═══════════════════════════╗
║ ID ║ PRICE ║ ITEMTRANSLATIONID ║ ITEMCATEGORYTRANSLATIONID ║
╠════╬═══════╬═══════════════════╬═══════════════════════════╣
║ 1 ║ 10 ║ 423 ║ 1323 ║
║ 2 ║ 31 ║ 1776 ║ 1953 ║
╚════╩═══════╩═══════════════════╩═══════════════════════════╝
Translations:
╔══════╦═══════════╦════════════╦═════════╗
║ ID ║ ENGLISH ║ FRENCH ║ GERMAN ║
╠══════╬═══════════╬════════════╬═════════╣
║ 1 ║ knife ║ couteau ║ messer ║
║ 2 ║ fork ║ fourchette ║ gabel ║
║ 423 ║ spoon ║ cuillère ║ löffel ║
║ 1323 ║ cultery ║ couverts ║ besteck ║
║ 1776 ║ table ║ table ║ tabelle ║
║ 1953 ║ furniture ║ meubles ║ möbel ║
╚══════╩═══════════╩════════════╩═════════╝
Is there a way to write an SQL query to get prices and translated names for each stock item? I will only ever need one language at once.
If only one column needed translating, I could just use an INNER JOIN. The trouble is, there are two columns that need translating- one for the item name, the other for the item category name.
i.e.
Required Output (French)
╔════╦═══════╦══════════╦══════════════╗
║ ID ║ PRICE ║ ITEM ║ ITEMCATEGORY ║
╠════╬═══════╬══════════╬══════════════╣
║ 1 ║ 10 ║ cuillère ║ couverts ║
║ 2 ║ 31 ║ table ║ meubles ║
╚════╩═══════╩══════════╩══════════════╝
join table Translations twice on table Stock so you could get the values for each columns in table Stock
SELECT a.ID, a.Price, b.French AS Item, c.French AS ItemCategory
FROM Stock a
INNER JOIN Translations b
ON a.ItemTranslationId = b.ID
INNER JOIN Translations c
ON a.ItemCategoryTranslationId = c.ID
SQLFiddle Demo
With this table structure, you would need to JOIN to the Translations table twice... once to get the Item, and again to get the ItemCategory:
SELECT
s.ID,
s.Price,
i.French AS Item,
ic.French AS ItemCategory
FROM
Stock s
JOIN Translations i ON i.ID = s.ItemTranslationId
JOIN Translations ic ON ic.ID = s.ItemCategoryTranslationId
You can use this query:
SELECT a.ID, a.Price,
(select French from Translations b where b.ID=a.ItemTranslationId) as ITEM,
(select French from Translations c where c.ID=a.ItemCategoryTranslationId) as ITEMCATEGORY
FROM Stock a

Ordering a table by time and based on the first appearance of an ID

I'm looking to order a log table so that it is grouped by id based on the first appearance of the id. In my example below, I have a table 'test' and I want to group the table by id so that all the ids are together, i.e. list all '623' entries then all '444' entries. I want the '623' entries to come first because the first '623' record came before the first '444' entries.
Input:
╔═══════╦════════════╦═════╗
║ uid ║ time ║ id ║
╠═══════╬════════════╬═════╣
║ 001 ║ 01:45:10 ║ 623 ║
║ 002 ║ 02:45:20 ║ 444 ║
║ 003 ║ 03:45:30 ║ 444 ║
║ 004 ║ 04:45:40 ║ 623 ║
║ 005 ║ 05:45:50 ║ 623 ║
║ 006 ║ 06:45:00 ║ 444 ║
╚═══════╩════════════╩═════╝
Output:
╔═══════╦════════════╦═════╗
║ uid ║ time ║ id ║
╠═══════╬════════════╬═════╣
║ 001 ║ 01:45:10 ║ 623 ║
║ 004 ║ 04:45:40 ║ 623 ║
║ 005 ║ 05:45:50 ║ 623 ║
║ 002 ║ 02:45:20 ║ 444 ║
║ 003 ║ 03:45:30 ║ 444 ║
║ 006 ║ 06:45:00 ║ 444 ║
╚═══════╩════════════╩═════╝
The closest I've come is this:
select time, id from test group by id, time
╔═══════╦════════════╦═════╗
║ uid ║ time ║ id ║
╠═══════╬════════════╬═════╣
║ 002 ║ 02:45:20 ║ 444 ║
║ 003 ║ 03:45:30 ║ 444 ║
║ 006 ║ 06:45:00 ║ 444 ║
║ 001 ║ 01:45:10 ║ 623 ║
║ 004 ║ 04:45:40 ║ 623 ║
║ 005 ║ 05:45:50 ║ 623 ║
╚═══════╩════════════╩═════╝
But this isn't exactly it because it's ordering by the id. I'm not sure what the proper syntax is to have all the '623' entries get listed first because the first '623' record came before the first '444' entry.
Thanks in advance for any help.
Got the answer:
SELECT test.time, test.id FROM
(
(SELECT DISTINCT id FROM test ORDER BY time ASC) as distinct_test
LEFT JOIN
test ON distinct_test.id = test.id
)
That makes sense now that I see it. Thanks everyone for the help.
Here is the code you need to use; I tested it on your data and it worked. It's basically the same as Jason Swett's, except you must use a LEFT OUTER JOIN rather than a RIGHT OUTER JOIN.
SELECT t.id, t.time
FROM (SELECT DISTINCT id
FROM `table`
ORDER BY time ASC) distinct_t
LEFT OUTER JOIN `table` t ON distinct_t.id = t.id;
Something like...
SELECT test.id,
test.time
FROM (SELECT DISTINCT id
FROM test
ORDER BY time ASC) distinct_test
RIGHT JOIN test ON distinct_test.id = test.id
That might not work but it might at least put you on your way.
Hmm?
SELECT time, id FROM test group by id, time order by id desc