Combining 2 tables to produce 1 output - SQL - mysql

I have a query below, and it works.
$query_for_cat3 = "SELECT sum,candidate_no,#curRank := #curRank + 1 AS rank
FROM (SELECT SUM(score) / 5 SUM,candidate_no
FROM SCORE
WHERE category_no='$category_no1'
GROUP BY candidate_no
) a, ( SELECT #curRank := 0 ) r
ORDER BY sum DESC,candidate_no DESC
LIMIT 5";
What I need to do is to combine this query to another table which is named candidates. It has columns candidate_no and candidate_name. I want to produce the candidate_name in respect to their corresponding candidate_no.
Please help. Thanks.

Is this is something you looking for?
SELECT temp.candidate_no,
C.candidatename,
temp.[sum],
temp.rank
FROM candidate C INNER JOIN
(SELECT sum,candidate_no,#curRank := #curRank + 1 AS rank
FROM (SELECT SUM(score) / 5 SUM,candidate_no
FROM SCORE
WHERE category_no='$category_no1'
GROUP BY candidate_no
) a, ( SELECT #curRank := 0 ) r
ORDER BY sum DESC,candidate_no DESC
LIMIT 5) As temp
ON C.candidate_no=temp.candidate_no

You can do a join like this
SELECT
table1.field
table2.field
FROM
table1
LEFT JOIN
table2
ON
table1.field=table2.field

If you want to select data from two table then you need to have primary-key or foreign key Method in both table...like if Candidate_no is in one table as primary key other table as Foreign key..then using this you can access data as::
select * from table_name1 where candidate_no=(select candidate_no from table_name2 where name="Charn");

Related

MySQL delete records between 'n' rows

I am trying to select records between let's say 2nd and 5th row. My id's are not in sequentially order so I tried to retrieve the row_number this way:
SELECT #curRow := #curRow + 1 AS row_number
FROM product_image p
JOIN (SELECT #curRow := 0) r
WHERE row_number BETWEEN 2 AND 5
My table is kind of:
id name
23 A
42 B
98 C
102 D
109 E
What I get is row_number column doesn't exist and it really does not exist. But how can retrieve the records between 2 and 5 ( 3th and 4th )? I red similar post but didn't understand the query well. Thank you in advance!
The reason the query fails is that you can't use column aliases in a WHERE clause. You can however use them in a GROUP BY and HAVING:
SELECT *, #curRow := #curRow + 1 AS row_number
FROM product_image p
JOIN (SELECT #curRow := 0) r
GROUP BY row_number
HAVING row_number between 2 and 5
Since you don't really need to select the row number, there is no need to rely on undocumented "features" like #curRow := #curRow + 1. Just use LIMIT and OFFSET. To select the rows from 2 to 5 you would just need
select id
from product_image
order by name, id
limit 4
offset 1
Note that you need a well defined ORDER BY clause. Otherwise the result can depend on what index has been used by the engine.
To delete those rows, use a DELETE .. JOIN statement
delete product_image
from product_image
join (
select id
from product_image
order by name, id
limit 4
offset 1
)x using(id)
Demo: http://sqlfiddle.com/#!9/66fa4/1
No tricks. No complex queries.
You can do a DELETE with JOIN:
DELETE p
FROM product_image p
INNER JOIN (
SELECT id, #curRow := #curRow + 1 AS row_number
FROM product_image p
CROSS JOIN (SELECT #curRow := 0) r
ORDER BY id
) AS t ON p.id = t.id
WHERE t.row_number IN (2,3)
Derived tabe t is created using your query. You can join to this table in order to identify any records you want and delete them.
Demo here
Check this -
http://sqlfiddle.com/#!9/c462d/5
select * from
(
SELECT #curRow := #curRow + 1 AS row_number,p.*
FROM product_image p
JOIN (SELECT #curRow := 0) r)
a
WHERE a. row_number BETWEEN 2 AND 5
To add a synthetic row number to a query, you need a subquery. Like so.
SELECT id FROM (
SELECT p.*, #curRow := #curRow + 1 AS row_number
FROM product_image p
JOIN (SELECT #curRow := 0) r
) q
WHERE row_number BETWEEN 2 AND 5
Then, you can, if you wish, use the result to drive a delete operation.
DELETE FROM product_image
WHERE id IN (
SELECT id FROM (
SELECT p.*, #curRow := #curRow + 1 AS row_number
FROM product_image p
JOIN (SELECT #curRow := 0) r
) q
WHERE row_number BETWEEN 2 AND 5
)
But this is an extremely bad thing to do. Why? You're relying on a particular order in the result set of your inner query. The rows in a SQL result set are, without any ORDER BY clause, returned in an unpredictable order. Server optimizers exploit this. Unpredictable is like random, but worse. Random implies that it's unlikely the order will be the same each time you run the query. Random here is good because you'll catch your problem during testing. Unpredictable, on the other hand, means the order remains the same until it doesn't. If you're not sure why that's bad, look up Murphy's law.

MySQL COUNT of distinct values from two independent columns of a table

I want to get the COUNT of distinct values from two independent columns of a table.
My table is:
ID CR PB DB CB
-----------------------------
1 1000 1000
2 60000 1000
3 1000 (NULL)
4 1500000 13000
5 60000 12000
6 1000 (NULL)
expected output:
CR PB cnt_crpb DB CB cnt_dbcb
1000 3 1000 2
60000 2 13000 1
1500000 1 12000 1
I have tried to separate both columns CR PB and DB CB in two different tables and joined them using LEFT JOIN but does not give expected output as MySQL does not support FULL OUTER JOIN.
I have also tried using UNION which but gives result in rows.
Any help will be appreciated...
Thanks you.
I think you need to do this using union all:
select max(CRPB) as CRPB, max(CRPB_cnt) as CRPB_cnt, max(DBCB) as DBCB, max(DBCB_cnt) as DBCB_cnt
from ((select (#rn1 := #rn1 + 1) as rn, CRPB, count(CRPB) as CRPB_cnt, NULL as DBCB, NULL as DBCB_cnt
from table t cross join
(select #rn1 := 0) as vars
group by CRPB
) union all
(select (#rn2 := #rn2 + 1) as rn, NULL, NULL, DBCB, count(DBCB) as DBCB_cnt
from table t cross join
(select #rn2 := 0) as vars
group by DBCB
)
) x
group by rn;
This will guarantee results regardless of which list is longest.
Note you need to determine which column will produce more results aka either CR PB or DB CB whichever produces the most results will be the first select you want to do then left join the other. assuming that there is an uneven number of results from the two
SELECT `CR PB`, cnt_crpb, `DB CB`, cnt_dbcb
FROM
( SELECT `CR PB`, COUNT(*) as cnt_crpb, #a := #a + 1 as num_rows_a
FROM test_table
CROSS JOIN (SELECT #a := 0 ) temp
WHERE `CR PB` is not null
GROUP BY `CR PB`
)t
LEFT JOIN
( SELECT `DB CB`, COUNT(*) as cnt_dbcb, #b := #b + 1 as num_rows_b
FROM test_table
CROSS JOIN (SELECT #b := 0)temp1
WHERE `DB CB` is not null
GROUP BY `DB CB`
)t1 ON t1.num_rows_b = t.num_rows_a;
Fiddle Demo

repeat result multiple times in mysql

I have a table having id and no field, what I really want is the result raw will be repeated no filed times, if the no field is 2 then that raw must be repeated twice in result.
this is my sample table structure:
id no
1 3
2 2
3 1
now I need to get a result like:
1 3
1 3
1 3
2 2
2 2
3 1
I tried to write mysql query to get the result like above, but failed.
You need a table of numbers to accomplish this. For just three values, this is easy:
select t.id, t.no
from t join
(select 1 as n union all select 2 union all select 3
) n
on t.no <= n.no;
This query must do what you want to achieve:
select t.id, t.no from test t cross join test y where t.id>=y.id
not completely solve your problem, but this one can help
set #i=0;
select
test_table.*
from
test_table
join
(select
#i:=#i+1 as i
from
any_table_with_number_of_rows_greater_than_max_no_of_test_table
where
#i < (select max(no) from test_table)) tmp on no >= i
order by
id desc
EDIT :
This is on SQL Server. I checked online and see that CTEs work on MySQL too. Just couldn't get them to work on SQLFiddle
Try this, remove unwanted columns
create table #temp (id int, no int)
insert into #temp values (1, 2),(2, 3),(3, 5)
select * from #temp
;with cte as
(
select id, no, no-1 nom from #temp
union all
select c.id, c.no, c.nom-1 from cte c inner join #temp t on t.id = c.id and c.nom < t.no and c.nom > 0
)
select * from cte order by 1
drop table #temp

Fetch 2nd Higest value from MySql DB with GROUP BY

I have a table tbl_patient and I want to fetch last 2 visit of each patient in order to compare whether patient condition is improving or degrading.
tbl_patient
id | patient_ID | visit_ID | patient_result
1 | 1 | 1 | 5
2 | 2 | 1 | 6
3 | 2 | 3 | 7
4 | 1 | 2 | 3
5 | 2 | 3 | 2
6 | 1 | 3 | 9
I tried the query below to fetch the last visit of each patient as,
SELECT MAX(id), patient_result FROM `tbl_patient` GROUP BY `patient_ID`
Now i want to fetch the 2nd last visit of each patient with query but it give me error
(#1242 - Subquery returns more than 1 row)
SELECT id, patient_result FROM `tbl_patient` WHERE id <(SELECT MAX(id) FROM `tbl_patient` GROUP BY `patient_ID`) GROUP BY `patient_ID`
Where I'm wrong
select p1.patient_id, p2.maxid id1, max(p1.id) id2
from tbl_patient p1
join (select patient_id, max(id) maxid
from tbl_patient
group by patient_id) p2
on p1.patient_id = p2.patient_id and p1.id < p2.maxid
group by p1.patient_id
id11 is the ID of the last visit, id2 is the ID of the 2nd to last visit.
Your first query doesn't get the last visits, since it gives results 5 and 6 instead of 2 and 9.
You can try this query:
SELECT patient_ID,visit_ID,patient_result
FROM tbl_patient
where id in (
select max(id)
from tbl_patient
GROUP BY patient_ID)
union
SELECT patient_ID,visit_ID,patient_result
FROM tbl_patient
where id in (
select max(id)
from tbl_patient
where id not in (
select max(id)
from tbl_patient
GROUP BY patient_ID)
GROUP BY patient_ID)
order by 1,2
SELECT id, patient_result FROM `tbl_patient` t1
JOIN (SELECT MAX(id) as max, patient_ID FROM `tbl_patient` GROUP BY `patient_ID`) t2
ON t1.patient_ID = t2.patient_ID
WHERE id <max GROUP BY t1.`patient_ID`
There are a couple of approaches to getting the specified resultset returned in a single SQL statement.
Unfortunately, most of those approaches yield rather unwieldy statements.
The more elegant looking statements tend to come with poor (or unbearable) performance when dealing with large sets. And the statements that tend to have better performance are more un-elegant looking.
Three of the most common approaches make use of:
correlated subquery
inequality join (nearly a Cartesian product)
two passes over the data
Here's an approach that uses two passes over the data, using MySQL user variables, which basically emulates the analytic RANK() OVER(PARTITION ...) function available in other DBMS:
SELECT t.id
, t.patient_id
, t.visit_id
, t.patient_result
FROM (
SELECT p.id
, p.patient_id
, p.visit_id
, p.patient_result
, #rn := if(#prev_patient_id = patient_id, #rn + 1, 1) AS rn
, #prev_patient_id := patient_id AS prev_patient_id
FROM tbl_patients p
JOIN (SELECT #rn := 0, #prev_patient_id := NULL) i
ORDER BY p.patient_id DESC, p.id DESC
) t
WHERE t.rn <= 2
Note that this involves an inline view, which means there's going to be a pass over all the data in the table to create a "derived tabled". Then, the outer query will run against the derived table. So, this is essentially two passes over the data.
This query can be tweaked a bit to improve performance, by eliminating the duplicated value of the patient_id column returned by the inline view. But I show it as above, so we can better understand what is happening.
This approach can be rather expensive on large sets, but is generally MUCH more efficient than some of the other approaches.
Note also that this query will return a row for a patient_id if there is only one id value exists for that patient; it does not restrict the return to just those patients that have at least two rows.
It's also possible to get an equivalent resultset with a correlated subquery:
SELECT t.id
, t.patient_id
, t.visit_id
, t.patient_result
FROM tbl_patients t
WHERE ( SELECT COUNT(1) AS cnt
FROM tbl_patients p
WHERE p.patient_id = t.patient_id
AND p.id >= t.id
) <= 2
ORDER BY t.patient_id ASC, t.id ASC
Note that this is making use of a "dependent subquery", which basically means that for each row returned from t, MySQL is effectively running another query against the database. So, this will tend to be very expensive (in terms of elapsed time) on large sets.
As another approach, if there are relatively few id values for each patient, you might be able to get by with an inequality join:
SELECT t.id
, t.patient_id
, t.visit_id
, t.patient_result
FROM tbl_patients t
LEFT
JOIN tbl_patients p
ON p.patient_id = t.patient_id
AND t.id < p.id
GROUP
BY t.id
, t.patient_id
, t.visit_id
, t.patient_result
HAVING COUNT(1) <= 2
Note that this will create a nearly Cartesian product for each patient. For a limited number of id values for each patient, this won't be too bad. But if a patient has hundreds of id values, the intermediate result can be huge, on the order of (O)n**2.
Try this..
SELECT id, patient_result FROM tbl_patient AS tp WHERE id < ((SELECT MAX(id) FROM tbl_patient AS tp_max WHERE tp_max.patient_ID = tp.patient_ID) - 1) GROUP BY patient_ID
Why not use simply...
GROUP BY `patient_ID` DESC LIMIT 2
... and do the rest in the next step?

Need a sequence number for every row in MySQL query

So I found this great use:
SELECT (#row:=#row+1) AS ROW, ID
FROM TableA ,(SELECT #row := 0) r
ORDER BY ID DESC
The #row:=#row+1 works great, but I get the row ordered by the ID.
My tables look more like this:
SELECT (#row:=#row+1) AS ROW, ID , ColA, ColB, ColC
FROM TableA
JOIN TableB on TableB.ID = TableA.ID
JOIN TableC on TableC.ID = TableA.ID
WHERE ID<500
,(SELECT #row := 0) r
ORDER BY ID DESC
Note:
I noticed that if I remove the JOINs I DO get the requested result (In Which ROW is the sequential number of each row, no matter the ORDER BY of ID). The first example works great but for some reaosn, the JOINs mess it up somehow.
so I get this:
ROW | ID
3 15
2 10
1 2
What I am after is:
ROW | ID
1 15
2 10
3 2
Here's the SqlFiddle
So it basically seems that the row number is evaluated before the ORDER BY takes place. I need the ORDER BY to take place after row was given.
How can I achieve that?
Remove the ORDER BY:
SELECT (#row:=#row+1) AS ROW, ID
FROM table1 ,(SELECT #row := 0) r
See SQL Fiddle with Demo
Then if you want to use an ORDER BY wrap the query in another SELECT:
select *
from
(
SELECT (#row:=#row+1) AS ROW, ID
FROM table1 ,(SELECT #row := 0) r
) x
order by row
Or if you leave the ORDER BY on the query, then you can see the way the row number is being applied by simply playing with either DESC or ASC order - See Demo
If you use DESC order
SELECT (#row:=#row+1) AS ROW, ID
FROM table1, (SELECT #row := 0) r
order by id desc;
the results are which appears to be the result you want:
ROW | ID
----------
1 | 15
2 | 10
3 | 2
If you use ASC order:
SELECT (#row:=#row+1) AS ROW, ID
FROM table1 ,(SELECT #row := 0) r
ORDER BY ID;
the results are:
ROW | ID
----------
1 | 2
2 | 10
3 | 15
Edit, based on your change, you should place the row number in a sub-query, then join the other tables:
select *
from
(
SELECT (#row:=#row+1) AS ROW, ID
FROM Table1,(SELECT #row := 0) r
order by ID desc
) x
JOIN Table2
on x.ID = Table2.ID;
See SQL Fiddle with Demo
I dont find any problem with your query
SELECT (#row:=#row+1) AS ROW, ID
FROM table1 ,(SELECT #row := 0) r
order by ID desc
SQL Fiddle demo