Merging two result sets - mysql

I know there are a number of questions here relating to what I am facing, but none of them are able to solve my situation.
I have two tables TABLE_1 and TABLE_2.
Table TABLE_1 has columns:
ID,
NAME
Table TABLE_2 has columns:
CODE,
AMOUNT,
QUANTITY
The two tables have a different number of columns but the row count is same.
Is possible to write an SQL query wherein I can retrieve all the columns from both the table in a single result set.
I am working on MySQL server.
Note: Both the tables have no common column. Any help is appreciated.
This is how I wish to retrieve:
| ID | NAME | CODE | AMOUNT | QUANTITY |
| | | | | |
| | | | | |
| | | | | |

Refer below query
SELECT a.ID, a.NAME, b.CODE,b.AMOUNT ,b.QUANTITY
FROM (SELECT
ROW_NUMBER() OVER(ORDER BY name ASC) AS RowNo, * FROM TABLE_1 )a
inner join (SELECT
ROW_NUMBER() OVER(ORDER BY CODE ASC) AS RowNo, * FROM TABLE_2 )b
On a.RowNo= b.RowNo

#Allan, here is my solution. Hope it helps.
CREATE TABLE t1(
ID INTEGER,
NAME VARCHAR(10)
);
CREATE TABLE t2(
CODE INTEGER,
AMOUNT INTEGER,
QUANTITY INTEGER
);
INSERT INTO t1 VALUES(91, 'Name1');
INSERT INTO t1 VALUES(92, 'Name2');
INSERT INTO t1 VALUES(93, 'Name3');
INSERT INTO t2 VALUES(1, 123, 2);
INSERT INTO t2 VALUES(2, 233, 4);
INSERT INTO t2 VALUES(3, 433, 1);
Query:
SET #rank=0;
SET #rank2=0;
select id,name,code,amount,quantity
from
(SELECT #rank:=#rank+1 AS rank, id, name
from t1) a,
(SELECT #rank2:=#rank2+1 AS rank, code, amount, quantity
from t2) b
where a.rank=b.rank;

Related

Preferential Select Query

The issue that we are trying to tackle is best shown with the following illustrative example:
CREATE TABLE table_1
(
id INT UNSIGNED AUTO_INCREMENT,
colA INT,
colB VARCHAR(10),
PRIMARY KEY(id)
);
CREATE TABLE table_2
(
id INT UNSIGNED AUTO_INCREMENT,
colY INT,
colZ VARCHAR(10),
PRIMARY KEY(id)
);
INSERT INTO table_1(colA, colB) VALUES(1, 'NPD5A6V9EI'), (2, 'ISO4IK42YQ'), (4, 'J12QAN4O42'), (6,'V8YTZFHCU4');
INSERT INTO table_2(colY, colZ) VALUES(3, 'RBUNWLO753'), (4, 'X2BCEY7O8B'), (5, 'BNUS7R4225'), (6, '72NOWCTH5G');
We would like to select our result based on the value of colA in table_1 but if that does not return a result , we would like to return our result based on the value of colY in table_2. In other words SELECTing from table_2 is the backup for SELECTing from table_1. The query returns NULL only if neither table satisfies the condition.
A pseudo SQL query could be:
SELECT colB FROM table_1 where colA = 3 OR SELECT colZ FROM table_2 where colY = 3;
The query should return output based on the following I/O table:
I O
= =
1 NPD5A6V9EI -- From table_1
2 ISO4IK42YQ -- From table_1
3 RBUNWLO753 -- From table_2
4 J12QAN4O42 -- From table_1 (has precedence over table_2 entry)
5 BNUS7R4225 -- From table_2
6 V8YTZFHCU4 -- From table_1 (has precedence over table_2 entry)
9 NULL
Kindly suggest solutions that:
make use of the latest DB features (for posterity)
work with MySQL version 5.6.51 (for our application)
Write a subquery that generates all the I rows that you want.
Then left join this with the two tables, and use IFNULL to take the matching value from table_1 in preference to table_2.
SELECT ids.id AS I, IFNULL(t1.colB, t2.colZ) AS O
FROM (SELECT 1 AS id UNION ALL SELECT 2 UNION ALL SELECT 3 ... UNION ALL SELECT 9) AS ids
LEFT JOIN table_1 AS t1 ON t1.colA = ids.id
LEFT JOIN table_2 AS t2 ON t2.colY = ids.id
ORDER BY ids.id
I simply don't kn ow where you get your last row.
also with Myql 8 you can ise the window function ROW_NUMBER
the rest is self explantory, the sorting comes from colA and Col1, when there are teh same numbers the second column orderby2 comes and sorts first for the first table
CREATE TABLE table_1
(
id INT UNSIGNED AUTO_INCREMENT,
colA INT,
colB VARCHAR(10),
PRIMARY KEY(id)
);
CREATE TABLE table_2
(
id INT UNSIGNED AUTO_INCREMENT,
colY INT,
colZ VARCHAR(10),
PRIMARY KEY(id)
);
INSERT INTO table_1(colA, colB) VALUES(1, 'NPD5A6V9EI'), (2, 'ISO4IK42YQ'), (4, 'J12QAN4O42'), (6,'V8YTZFHCU4');
INSERT INTO table_2(colY, colZ) VALUES(3, 'RBUNWLO753'), (4, 'X2BCEY7O8B'), (5, 'BNUS7R4225'), (6, '72NOWCTH5G');
SELECT #i := #i +1 AS I,
colB AS O
FROM
(SELECT colA as orderby1,colB,1 ordberby2 froM table_1
UNION
SELECT colY, colZ,2 froM table_2 ) t1,(SELECT #i := 0) t2
ORDER BY orderby1,ordberby2
I | O
-: | :---------
1 | NPD5A6V9EI
2 | ISO4IK42YQ
3 | RBUNWLO753
4 | J12QAN4O42
5 | X2BCEY7O8B
6 | BNUS7R4225
7 | V8YTZFHCU4
8 | 72NOWCTH5G
db<>fiddle here

Show id and Count the same Foreign Key

I'm using MySql. I have a table with 2 column id (Primary Key) and id_of (Foreign Key). Number of id can have the same id_of. I want to get all the id and get the count of rows having the id_of related to the id. How to make this sql query/queries? So far I could only get this:
SELECT id, (SELECT COUNT(id_of) FROM test_table) AS count FROM test_table;
database's table:
id | id_of
----------------
abasb | 2131233
hdafd | 2131233
fajdf | 3546541
pogad | 3546541
afdaj | 2131233
fafda | 8661565
the results I want:
id | count
----------------
abasb | 3
hdafd | 3
fajdf | 2
pogad | 2
afdaj | 3
fafda | 1
just need a bit of correction your query
SELECT id,
(SELECT COUNT(*) FROM test_table t2 where t2.id_of=t1.id_of) AS count
FROM test_table t1
You may try this...
; with cte as ( select distinct id_of, count(*) as Coun from testtable )
select t.id , c.coun from testtable as t inner join cte as c on t.id_of=c.id_of
You can try this:
select id , count(*) over (partition by id_of) id_of from Yourtable
You could use ajoin on subqiery for count
select a.id, t.count_of_id_of
from test_table a
inner join (
select id_of, count(*) count_of_id_of
from test_table
group by id_of
) t on t.id_of= a.id_of

MYSQL Updating row to maximum value of similar rows

I have a table like this in MYSQL:
ID | NAME | VALUE |
----------------------------
1 | Bob | 1 |
2 | Bob | 2 |
3 | Jack | 5 |
4 | Jack | 8 |
5 | Jack | 10 |
and I'm trying to update the VALUE column to the highest value of rows with same NAME. So the result should be:
ID | NAME | VALUE |
----------------------------
1 | Bob | 2 |
2 | Bob | 2 |
3 | Jack | 10 |
4 | Jack | 10 |
5 | Jack | 10 |
I managed to get the max value like this:
SELECT MAX(Value) max FROM `table` GROUP BY Name having count(*) >1 AND MAX(Value) != MIN(Value)
But can't figure out how to put it in my update
Update table set Value = (SELECT MAX(Value) max FROM `table` GROUP BY Name having count(*) >1 AND MAX(Value) != MIN(Value))
Doesn't work. I'd appreciate any help.
This is easier than other answers are making it.
UPDATE MyTable AS t1 INNER JOIN MyTable AS t2 USING (Name)
SET Value = GREATEST(t1.Value, t2.Value);
You don't have to find the largest value. You just have to join each row to the set of rows with the same name, and set the Value to the greater Value of the two joined rows. This is a no-op on some rows, but it will apply to every row in turn.
http://sqlfiddle.com/#!9/f79a3/1
UPDATE t1
INNER JOIN (SELECT name, MAX(`value`) max_value
FROM t1 GROUP BY name) t2
ON t1.name = t2.name
SET t1.value = t2.max_value;
Create a temporary table consisting of ID NAME and MAX VALUE as follows:
CREATE TEMP TABLE TABLE1 AS
(SELECT NAME,MAX(Value) value FROM `table` GROUP BY Name having count(*) >1
AND MAX(Value) != MIN(Value)
);
Use this temporary table to do your update as follows:
UPDATE
Table_A
SET
Table_A.value = Table_B.value
FROM
`table` AS Table_A
INNER JOIN TABLE1 AS Table_B
ON Table_A.NAME = Table_B.NAME
Also this code is somewhat of an approximation as i am not familiar with mysql but i am familiar with sql.
Let me know if this doesn't help.
Simple left join would do the trick.
Try this out and let me know in case of any queries.
select a.id,a.name,b.value
from
table a
left join
(select name,max(value) as value from table group by name) b
on a.name=b.name;
You may use this query. The table is joined with a subquery (table t2) that contains the results you want to update your table with:
UPDATE `table` t1,
(SELECT Name, MAX(Value) maxv, MIN(Value) minv
FROM `table`
GROUP BY Name
HAVING COUNT(*)>1 AND maxv != minv) t2
SET t1.Value = t2.maxv
WHERE t1.Name = t2.Name;
If you want to know how will the values be updated, you can first run an equivalent SELECT query:
SELECT t1.*, t2.maxv
FROM `table` t1,
(SELECT Name, MAX(Value) maxv, MIN(Value) minv
FROM `table`
GROUP BY Name
HAVING COUNT(*)>1 AND maxv != minv) t2
WHERE t1.Name = t2.Name;
This query will display all the fields of table, followed by the new value maxv. You can check the current value and the new value, and if it looks fine, you may run the UPDATE query.

SQL: How to make a conditional COUNT and SUM

Let's say I have the following table:
id | letter | date
--------------------------------
1 | A | 2011-01-01
2 | A | 2011-04-01
3 | A | 2011-04-01
4 | B | 2011-01-01
5 | B | 2011-01-01
6 | B | 2011-01-01
I would like to make a count of the rows broken down by letter and date, and sum the count of all the previous dates. every letter should have a row to every date of the table (ie. letter B doesn't have a 2011-04-01 date, but still appears in the result)
The resulting table would look like this
letter| date | total
--------------------------------
A | 2011-01-01 | 1
A | 2011-04-01 | 3
B | 2011-01-01 | 3
B | 2011-04-01 | 3
How to achieve this in a SQL query?
Thank you for your help!
NOTE
I didn't notice it was mysql, which doesn't support CTE. You may be able to define temporary tables to use this.
This is an interesting problem. You kind of need to join all letters with all dates and then count the preceding rows. If you weren't concerned with having rows for letters that have a count of 0 for the dates, you could probably just do something like this:
SELECT letter, date,
(SELECT COUNT(*)
FROM tbl tbl2
WHERE tbl2.letter = tbl1.letter
AND tbl2.date <= tbl1.date) AS total
FROM tbl
ORDER BY date, letter
/deleted CTE solution/
Solution without CTE
SELECT tblDates.[date], tblLetters.letter,
(SELECT COUNT(*)
FROM tblData tbl2
WHERE tbl2.letter = tblLetters.letter
AND tbl2.[date] <= tblDates.[date]) AS total
FROM (SELECT DISTINCT [date] FROM tblData) tblDates
CROSS JOIN (SELECT DISTINCT letter FROM tblData) tblLetters
ORDER BY tblDates.[date], tblLetters.letter
The requirement
every letter should have a row to every date of the table
requires a cross join of the distinct dates and letters. Once you do that its pretty straight forward
SELECT letterdate.letter,
letterdate.DATE,
COUNT(yt.id) total
FROM (SELECT letter,
date
FROM (SELECT DISTINCT DATE
FROM yourtable) dates,
(SELECT DISTINCT letter
FROM yourtable) letter) letterdate
LEFT JOIN yourtable yt
ON letterdate.letter = yt.letter
AND yt.DATE < yt.letter
GROUP BY letterdate.letter,
letterdate.DATE
A slight variation on the previous:
declare #table1 table (id int, letter char, date smalldatetime)
insert into #table1 values (1, 'A', '1/1/2011')
insert into #table1 values (2, 'A', '4/1/2011')
insert into #table1 values (3, 'A', '4/1/2011')
insert into #table1 values (4, 'B', '1/1/2011')
insert into #table1 values (5, 'B', '1/1/2011')
insert into #table1 values (6, 'B', '1/1/2011')
select b.letter, b.date, count(0) AS count_
from (
select distinct letter, a.date from #table1
cross join (select distinct date from #table1 ) a
) b
join #table1 t1
on t1.letter = b.letter
and t1.date <= b.date
group by b.letter, b.date
order by b.letter

Question on multi-row insertion with subqueries

Say I have the following 2 tables,
CREATE TABLE t1(
name VARCHAR(25) NOT NULL,
time INT,
a INT
);
CREATE TABLE t2(
name VARCHAR(25) NOT NULL,
time INT,
b INT
);
and Im looking to pull all the values (a) out of t1 with a given time, all the values with the previous time (say just time-1 for convenience) then for each name subtract the newer one from the older one and insert those values into t2 with the same time. The slow way of doing this would involve doing something like
SELECT name, a FROM t1 WHERE time = x;
SELECT name, a FROM t1 WHERE time = x-1;
(subtract the as for each name)
INSERT INTO t2 VALUES ....;
From my (limited) understanding of subqueries, there should hopefully be a way to do this all in 1 query. Any ideas? Thanks in advance :)
It looks like you can use the INSERT ... SELECT syntax:
INSERT INTO t2 (name, time, b)
SELECT ta.name, ta.time time, (ta.a - tb.a) b
FROM t1 ta
JOIN t1 tb ON (tb.time = ta.time - 1 AND tb.name = ta.name);
Test case:
INSERT INTO t1 VALUES ('t1', 1, 100);
INSERT INTO t1 VALUES ('t1', 2, 200);
INSERT INTO t1 VALUES ('t1', 3, 500);
INSERT INTO t1 VALUES ('t1', 4, 600);
INSERT INTO t1 VALUES ('t1', 5, 800);
INSERT INTO t1 VALUES ('t1', 6, 900);
Result:
SELECT * FROM t2;
+------+------+------+
| name | time | b |
+------+------+------+
| t1 | 2 | 100 |
| t1 | 3 | 300 |
| t1 | 4 | 100 |
| t1 | 5 | 200 |
| t1 | 6 | 100 |
+------+------+------+
5 rows in set (0.00 sec)
there is im mysql insert ... select
INSERT INTO table ( fields )
SELECT fields FROM table;