MYSQL: How to fill null values in column with the previous entry? - mysql

I've got a program at work that exports to CSV but leaves blanks in the most irritable places. I want to view the carrier and destination on the same row and currently the carrier is 1 row above the destination like below:
I have a database that is like the following:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | || C14A102 |
| 3 | DONC1 || |
| 4 | || D15A012 |
What I want:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | HULL2 || C14A102 |
| 3 | DONC1 || |
| 4 | DONC1 || D15A012 |
Either that or insert a new column with the information from carrier column.
Sorry if this is confusing its confusing me to explain it!
James

Here is a solution, by cloning another table and then deleting it:
CREATE TABLE t1(Key_id INT PRIMARY KEY, Carrier CHAR(20), Destination CHAR(20));
INSERT INTO t1 VALUES(1, 'HULL2', ''),(2,'','C14A102'),(3,'DONC1',''),(4,'','D15A012');
CREATE TABLE t2 LIKE t1;
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t1;
UPDATE t1 SET Carrier =
(
SELECT t2.Carrier
FROM t2
WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
ORDER BY t2.Key_id DESC
LIMIT 1
)
WHERE Carrier = '';
SELECT * FROM t1;
DROP TABLE t2;
Output:
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | | C14A102 |
| 3 | DONC1 | |
| 4 | | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
mysql> UPDATE t1 SET Carrier =
-> (
-> SELECT t2.Carrier
-> FROM t2
-> WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
-> ORDER BY t2.Key_id DESC
-> LIMIT 1
-> )
-> WHERE Carrier = '';
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | HULL2 | C14A102 |
| 3 | DONC1 | |
| 4 | DONC1 | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)

Assuming that the column 'key' can be trusted in this way, I would update with a self join where the join uses key = key+1, and then make sure it's only affecting even rows.
UPDATE tablename as even_row JOIN tablename as odd_row
ON even_row.Key = odd_row.Key + 1
SET even_row.Carrier = odd_row.Carrier
WHERE odd_row.Key % 2;

Related

MySQL Count name greater than a value

Please how can i check if a particular name is greater than a value in MySQL database. I want to do something like.
SELECT id FROM table WHERE COUNT(name = 'john') > 2
i know this does not work, but i really need to do something like this.
An Example: A student studying CS, From New York, and grad point is 4.5 wants to check into a hostel.
I have a hostel tables with fields course, state, and Grade_Point. i want to select the hostel_id where no same user with the same course > 2, state > 2 and grade_point > 2 are in the same room.
You can use the HAVING clause :
SELECT t.id FROM YourTable t
GROUP BY id
HAVING SUM(t.name = 'john') > 2
MySQL takes boolean expression as 0,1 , so SUM(t.name = 'john') will sum the number of occurences john appears for each ID , and will bring back those that appear more then twice.
Assuming that id is not unique and you want ids where 'john' appears 3 or more times:
select id
from t
where name = 'john'
group by id
having count(*) > 2;
This should be more efficient than any version that uses conditional aggregation because it reduces the size of the data before doing the aggregation.
Try this;)
SELECT id FROM table HAVING COUNT(IF(name = 'john', 1, null)) > 2
SELECT name, count(*)
FROM YourTable
where name = 'john'
GROUP BY name
HAVING count(*) > 2
Consiedr the following...
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
+----+------+
INSERT INTO my_table (name) SELECT 'Q' FROM (SELECT 1) x LEFT JOIN my_table y ON y.name = 'Q' WHERE y.id IS NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
+----+------+
INSERT INTO my_table (name) SELECT 'Z' FROM (SELECT 1) x LEFT JOIN my_table y ON y.name = 'Z' WHERE y.id IS NULL;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
| 7 | Z |
+----+------+
7 rows in set (0.00 sec)
Alternatively, you can just issue a simple INSERT on a UNIQUE column. And use the 'rows affected' as evidence of whether the name already exists.

Simplify subquery mysql to get all column in relation table

I have a table named tb_customer master.
mysql> select COSTUMER_ID, NAMA, ATTENTION, IN_DATE, IN_REF, JOB_REF, LAST_CARGO FROM tb_customer_master;
+-------------+----------------------+-------------------------+------------+--------+---------+----------------------+
| COSTUMER_ID | NAMA | ATTENTION | IN_DATE | IN_REF | JOB_REF | LAST_CARGO |
+-------------+----------------------+-------------------------+------------+--------+---------+----------------------+
| 2 | Eagletainer | Ms. Joyce Ong Chong Mei | NULL | 1234 | 123 | Lube |
| 5 | APL | Test | 21-11-2015 | sgdgfa | sgfsd | FOOD |
+-------------+----------------------+-------------------------+------------+--------+---------+----------------------+
2 rows in set (0.00 sec)
And I have table too as table master that have behavior as a report master
mysql> select REPAIR_ESTIMATE_ID, EIR_REF, COSTUMER_ID FROM tb_master_repair_estimate;
+--------------------+------------+-------------+
| REPAIR_ESTIMATE_ID | EIR_REF | COSTUMER_ID |
+--------------------+------------+-------------+
| 38 | 1545053 | 5 |
| 40 | 1545052 | 5 |
| 41 | 1545054 | 5 |
+--------------------+------------+-------------+
3 rows in set (0.00 sec)
Now, for a case, I want to subquery of them like this
mysql> SELECT
-> a.EIR_REF as EIR,
->
-> (SELECT NAMA FROM tb_customer_master c
-> WHERE a.COSTUMER_ID = c.COSTUMER_ID ) as "Name Of Customer",
->
-> (SELECT ATTENTION FROM tb_customer_master c
-> WHERE a.COSTUMER_ID = c.COSTUMER_ID ) as "ATTENTION"
->
-> FROM tb_master_repair_estimate a
->
-> WHERE a.EIR_REF = "1545052";
+------------+----------------------+-----------+
| EIR | Name Of Customer | ATTENTION |
+------------+----------------------+-----------+
| 1545052 | APL | Test |
+------------+----------------------+-----------+
1 row in set (0.00 sec)
My question is, I want to make my last query to be simply. How can I make With a one column eir, name of customer, attention, in_date, in_ref and so on to be simply, not as select one by one in subquery. It is so long command if determine it one by one.
Any suggestion so appreciated
UPDATE,
Thanks for the quickly response. Ther reason why I am using subquery is because my table of report master have many foreign key.
This is the complete tbl_report
mysql> select EIR_REF, NO_TANK, COSTUMER_ID, TANK_ID, TOTAL from tb_master_repair_estimate where EIR_REF = "1545052";
+------------+---------+-------------+---------+-------+
| EIR_REF | NO_TANK | COSTUMER_ID | TANK_ID | TOTAL |
+------------+---------+-------------+---------+-------+
| 1545052 | 7 | 5 | 1 | NULL |
+------------+---------+-------------+---------+-------+
And another table again named tb_tank_type
mysql> select * from tb_tank_type;
+---------+-----------+------------+
| TANK_ID | NAMA_TYPE | KETERANGAN |
+---------+-----------+------------+
| 1 | IM04 | NULL |
| 2 | XXXX | NULL |
+---------+-----------+------------+
2 rows in set (0.00 sec)
I am try to make them on one unite using my code like this:
mysql> SELECT
-> a.EIR_REF as EIR,
->
-> (SELECT NAMA_TYPE FROM tb_tank_type b
-> WHERE b.TANK_ID = a.TANK_ID) as "type tank",
->
-> (SELECT NAMA FROM tb_customer_master c
-> WHERE a.COSTUMER_ID = c.COSTUMER_ID ) as "Name Of Customer",
->
-> (SELECT ATTENTION FROM tb_customer_master c
-> WHERE a.COSTUMER_ID = c.COSTUMER_ID ) as "ATTENTION",
->
-> (SELECT PREFIX FROM tb_iso_tanks d
-> WHERE a.NO_TANK = d.ID_TANK) as "PREFIX",
->
-> (SELECT SERIAL_NUMBER FROM tb_iso_tanks d
-> WHERE a.NO_TANK = d.ID_TANK) as "SERIAL_NUMBER"
->
-> FROM tb_master_repair_estimate a
->
-> WHERE a.EIR_REF = "1545052";
+------------+-----------+----------------------+-----------+--------+---------------+
| EIR | type tank | Name Of Customer | ATTENTION | PREFIX | SERIAL_NUMBER |
+------------+-----------+----------------------+-----------+--------+---------------+
| 1545052 | IM04 | APL | Test | EOLU | 1234567 |
+------------+-----------+----------------------+-----------+--------+---------------+
1 row in set (0.00 sec)
Btw, thanks again.
So a case like this :
There are another table again.
JOINs are usually much faster, and simpler, than subqueries:
SELECT a.EIR_REF as EIR, c.NAMA AS `Name of Customer`, c.ATTENTION AS ATTENTION
FROM tb_master_repair_estimate a
LEFT JOIN tb_customer_master c USING (COSTUMER_ID)
WHERE a.EIR_REF = "1545052"
;
If I understand it correctly, you might use a JOIN your table tb_customer_master to your table tb_master_repair_estimate to simplify your query.
Example derived from your statement:
SELECT
a.EIR_REF as EIR,
c.NAMA as "Name Of Customer",
c.ATTENTION as "ATTENTION"
FROM tb_master_repair_estimate a
INNER JOIN tb_customer_master c ON a.COSTUMER_ID = b.COSTUMER_ID
WHERE a.EIR_REF = "1545052";
Another benefit: this is way more readable.
Looks like you would need to use a join in this instance:
select a.EIR_REF, c.NAMA, c.ATTENTION
from tb_master_repair_estimate a
join tb_customer_master c
on c.COSTUMER_ID = a.COSTUMER_ID
where a.EIR_REF = '1545052';

Make new column which is incremented by it's order

I need to make new column for my table Products -> called Order (new column). And using rails migration I need to add new column and instantly set it's order number, but it's need to be done by product_id.
What I mean I need something like:
product_id | order
1 ------------> 1
1 ------------> 2
1 ------------> 3
2 ------------> 1
2 ------------> 2
Is there a way of doing it?
EDIT :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''order' = t1.'order'' at line 15:
update product_submissions t
join (
select
id,
product_id,
'order' from (
select id,
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as 'order',
#prev:=product_id
from product_submissions,
(select #rn:=0,#prev:=0)r
order by product_id,id
)x
)t1 on t1.id=t.id set t.'order' = t1.'order'
Consider the following
mysql> create table test (id int ,product_id int);
Query OK, 0 rows affected (0.14 sec)
mysql> insert into test values (1,1),(2,1),(3,1),(4,2),(5,2);
Now lets create the order
select
product_id,
`order` from (
select
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as `order`,
#prev:=product_id from test,(select #rn:=0,#prev:=0)r
order by product_id,id
)x ;
This will give you something as
+------------+-------+
| product_id | order |
+------------+-------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
+------------+-------+
Now lets use in update command, but before that lets add the column (in your case its already there)
mysql> alter table test add column `order` int ;
Query OK, 5 rows affected (0.29 sec)
mysql> select * from test ;
+------+------------+-------+
| id | product_id | order |
+------+------------+-------+
| 1 | 1 | NULL |
| 2 | 1 | NULL |
| 3 | 1 | NULL |
| 4 | 2 | NULL |
| 5 | 2 | NULL |
+------+------------+-------+
5 rows in set (0.00 sec)
Finally the update command
update test t
join (
select
id,
product_id,
`order` from (
select id,
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as `order`,
#prev:=product_id
from test,(select #rn:=0,#prev:=0)r
order by product_id,id
)x
)t1 on t1.id=t.id set t.`order` = t1.`order`
mysql> select * from test ;
+------+------------+-------+
| id | product_id | order |
+------+------------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
+------+------------+-------+
5 rows in set (0.00 sec)

List all associate's names from a referred table?

I have a table test which looks like this:
+-------+-------+
| u1_id | u2_id |
+-------+-------+
| 1 | 2 |
| 3 | 1 |
| 2 | 1 |
| 2 | 3 |
+-------+-------+
And, u1_id and u2_id are both 'foreign keys' to another table user:
+----+-------+
| id | name |
+----+-------+
| 1 | n_foo |
| 2 | n_bar |
| 3 | n_baz |
+----+-------+
Not sure how to explain this, but:
In input, I have a single user id which can be referenced in u1_id or in u2_id.
I'd like to get the associated user to it as defined in table test using a join on table user.
For user id = 1, I should get:
n_bar
n_baz
n_bar
For user id = 2, I should get:
n_foo
n_foo
n_baz
This may be a common issue but didn't find exactly how to join these two tables using:
u1_id if my input user id is in u2_id column
u2_id otherwise
I tried something like this but it doesn't seem to work:
SELECT name
FROM test
JOIN user
ON user.id = test.u1_id
WHERE test.u1_id = #guid OR
test.u2_id = #guid AND
CASE
WHEN test.u2_id = #guid
THEN test.u2_id = test.u1_id
END;
Any ideas how to achieve this? Or may be there is a better way to design these tables, I'm completely open to any suggestions.
If I correctly understood your question, I believe you need following query:
SELECT t2.`name`
FROM `t2`
INNER JOIN (
SELECT IF(#uid = 1, t1.u1_id, t1.u2_id) as `id`
FROM `t1`
) as `t1`
WHERE t2.id = t1.id and t1.id != #uid;
I tried following:
Date base create, I don't know what columns type your are using just for demo:
create table t1 (
u1_id int,
u2_id int
);
insert into t1 values
(1, 2),
(3, 1),
(2, 1),
(2, 3);
create table t2 (
id int,
name varchar(10)
);
insert into t2 values
( 1 , 'n_foo' ),
( 2 , 'n_bar' ),
( 3 , 'n_baz' );
Then Queries:
mysql> SELECT * FROM t1;
+-------+-------+
| u1_id | u2_id |
+-------+-------+
| 1 | 2 |
| 3 | 1 |
| 2 | 1 |
| 2 | 3 |
+-------+-------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM t2;
+------+-------+
| id | name |
+------+-------+
| 1 | n_foo |
| 2 | n_bar |
| 3 | n_baz |
+------+-------+
3 rows in set (0.00 sec)
mysql> SET #uid = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #uid;
+------+
| #uid |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> SELECT t2.`name`
-> FROM `t2`
-> INNER JOIN (
-> SELECT IF(#uid = 1, t1.u1_id, t1.u2_id) as `id`
-> FROM `t1`
-> ) as `t1`
-> WHERE t2.id = t1.id and t1.id != #uid;
+-------+
| name |
+-------+
| n_baz |
| n_bar |
| n_bar |
+-------+
3 rows in set (0.03 sec)
mysql> SET #uid = 2;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #uid;
+------+
| #uid |
+------+
| 2 |
+------+
1 row in set (0.00 sec)
mysql> SELECT t2.`name`
-> FROM `t2`
-> INNER JOIN (
-> SELECT IF(#uid = 1, t1.u1_id, t1.u2_id) as `id`
-> FROM `t1`
-> ) as `t1`
-> WHERE t2.id = t1.id and t1.id != #uid;
+-------+
| name |
+-------+
| n_foo |
| n_foo |
| n_baz |
+-------+
3 rows in set (0.00 sec)
Btw, you can change join conditions if it is not what you wanted. But as it give correct results...
Give it a Try!!
What about:
SELECT IF(u1.id = #guid, u2.name, u1.name) AS name
FROM test
JOIN user u1 ON u1.id = test.u1_id
JOIN user u2 ON u2.id = test.u2_id
WHERE test.u1_id=#guid OR test.u2_id=#guid;
Using #GrijeshChauhan's schema...
SELECT * FROM
(SELECT u1_id,u2_id FROM t1
UNION ALL
SELECT u2_id,u1_id FROM t1
) x
JOIN t2
ON t2.id = x.u1_id
WHERE x.u2_id = 2;
+-------+-------+------+-------+
| u1_id | u2_id | id | name |
+-------+-------+------+-------+
| 1 | 2 | 1 | n_foo |
| 1 | 2 | 1 | n_foo |
| 3 | 2 | 3 | n_baz |
+-------+-------+------+-------+

MySQL riddle with subquery

EDIT: looks like an index issue, update at the bottom of the question
I have the following query + subquery whose results I cannot explain. I am starting with this minimal input data set (the application here is capturing data change, and the PK is the id + the tx_id).
mysql> select * from tag_version;
+----+-------------------+------------+-------+----------------+
| id | name | article_id | tx_id | operation_type |
+----+-------------------+------------+-------+----------------+
| 1 | some tag | 1 | 1 | 0 |
| 1 | updated tag | 1 | 2 | 1 |
| 1 | updated again tag | 1 | 3 | 1 |
| 2 | other tag | 1 | 2 | 0 |
+----+-------------------+------------+-------+----------------+
4 rows in set (0.00 sec)
The subquery, standalone
SELECT max(f.tx_id) as max_tx_id, f.id
from tag_version f
WHERE f.tx_id <= 2
GROUP BY f.id
Result is
+-----------+----+
| max_tx_id | id |
+-----------+----+
| 2 | 1 |
| 2 | 2 |
+-----------+----+
2 rows in set (0.00 sec)
The query, where I manually inject the subquery results, notice how they are equal to the above
select t.*
from tag_version t
where t.article_id = 1
AND (t.tx_id, t.id) IN (
(2,1),
(2,2)
)
With expected results
+----+-------------+------------+-------+----------------+
| id | name | article_id | tx_id | operation_type |
+----+-------------+------------+-------+----------------+
| 1 | updated tag | 1 | 2 | 1 |
| 2 | other tag | 1 | 2 | 0 |
+----+-------------+------------+-------+----------------+
2 rows in set (0.00 sec)
And lastly, using the subquery in place of the tuples...
select t.*
from tag_version t
where t.article_id = 1
AND (t.tx_id, t.id) IN (
SELECT max(f.tx_id) as tx_id, f.id
from tag_version f
WHERE f.tx_id <= 2
GROUP BY f.id
)
The result is Empty set (0.00 sec)! Can someone explain this? I get the same empty results when I re-write the query using EXISTS instead of IN
I noticed than when I remove the line WHERE f.tx_id <= 2 from the subquery, I actually get results (although the wrong ones):
+----+-------------------+------------+-------+----------------+
| id | name | article_id | tx_id | operation_type |
+----+-------------------+------------+-------+----------------+
| 1 | updated again tag | 1 | 3 | 1 |
| 2 | other tag | 1 | 2 | 0 |
+----+-------------------+------------+-------+----------------+
2 rows in set (0.00 sec)
Replacing the subquery with a JOIN actually returns the expected correct results
SELECT t.*
FROM tag_version t
JOIN (
SELECT max(f.tx_id) as max_tx_id, f.id
from tag_version f
WHERE f.tx_id <= 2
GROUP BY f.id
) as max_ids
ON max_ids.max_tx_id = t.tx_id
AND max_ids.id = t.id
where t.article_id = 1
Result:
+----+-------------+------------+-------+----------------+
| id | name | article_id | tx_id | operation_type |
+----+-------------+------------+-------+----------------+
| 1 | updated tag | 1 | 2 | 1 |
| 2 | other tag | 1 | 2 | 0 |
+----+-------------+------------+-------+----------------+
2 rows in set (0.00 sec)
In addition, running the same query+subquery on the same data set with both PostgreSQL and SQLite gives the expected correct results.
My MySQL version is Server version: 5.5.40-0ubuntu0.14.04.1 (Ubuntu).
I think the clue to figuring out what's happening is that I actually get results when I remove the WHERE from the subquery, but I can't make something useful out of it.
EDIT: updated with input data set
EDIT: add table information
The table create statement is as follows
CREATE TABLE `tag_version` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`article_id` int(11) DEFAULT NULL,
`tx_id` bigint(20) NOT NULL,
`operation_type` smallint(6) NOT NULL,
PRIMARY KEY (`id`,`tx_id`),
KEY `ix_tag_version_operation_type` (`operation_type`),
KEY `ix_tag_version_tx_id` (`tx_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Data population as well
insert into tag_version (id, name, article_id, tx_id, operation_type) VALUES
(1, 'some tag', 1, 1, 0),
(1, 'updated tag', 1, 2, 1),
(1, 'updated again tag', 1, 3, 1),
(2, 'other tag', 1, 2, 0)
;
When I remove the ix_tag_version_tx_id index, the query returns the correct results... An explanation of why would be useful.
I believe you made a mistake in showing the result of first code(subquery).
The output of this query:
SELECT max(f.tx_id) as qwer, f.id
from tag_version f
WHERE f.tx_id <= 2
GROUP BY f.id
-is not:
+--------------+----+
| max(f.tx_id) | id |
+--------------+----+
| 2 | 1 |
| 2 | 2 |
+--------------+----+
It is:
+------+----+
| qwer | id |
+------+----+
| 2 | 1 |
| 2 | 2 |
+------+----+
(*Notice: the code line max(f.tx_id) as qwer *)
Now try this code for the expexted output.
There is a change when selecting max(f.tx_id).
select t.*
from tag_version t
where t.`article_id` = 1
AND t.`operation_type` != 2
AND (t.`tx_id`, t.`id`) IN (
SELECT max(f.`tx_id`) as `tx_id`, f.`id`
from tag_version f
WHERE f.`tx_id` <= 2
GROUP BY f.`id`
)
Let me know if this gives you the result or any other error.