How Can Identify Table in Mysql Union All - php

I Have Query As the following
SELECT * FROM (
(
SELECT * FROM comments
WHERE user_id = '66' AND product_id = '3'
AND status = 1
)
UNION ALL
(
SELECT * FROM comments_reply
WHERE user_id = '66' AND product_id = '3'
AND status = 1 )
) results
ORDER BY datetime DESC
Which Gets Data from two tabel and shows it in order to datetime.now frontside i am showing this data. but now i wants to know that which data is came from which table.
because I am calling a modal to show a comment in modal by this
<span class="showcomment text-danger"
data-cid = <?=$row[0]?>>view Comment</span>
But $row[0] Gives me an id But How can i identify that this id is came from which Table ?

I would rewrite your query as with tablename that you want
SELECT 'comments' as table_name, col1, col2,... coln FROM comments c
WHERE user_id = '66' AND product_id = '3'
AND status = 1 UNION ALL
SELECT 'comments_reply' as table_name, col1, col2,... coln FROM comments_reply cr
WHERE user_id = '66' AND product_id = '3'
ORDER BY col DESC
And, i suspect if you have user_id, product_id has numeric type then you should use only values without single quote.
where user_id = 66 AND product_id = 3

You can add a column to each of your two tables and populate it with a custom string. For example, the first sub query would start like the following with the new column “table_name”... select *, ‘comments’ table_name from comments...

SELECT * FROM (
(
SELECT "comments" as tablename,* FROM comments
WHERE user_id = '66' AND product_id = '3'
AND status = 1
)
UNION ALL
(
SELECT "comments_reply" as tablename,* FROM comments_reply
WHERE user_id = '66' AND product_id = '3'
AND status = 1 )
) results
ORDER BY datetime DESC

Related

Mysql limit results based on value from column

I'm trying to limit the number of results of a query based on another table column. For example, I have a table for products and a config table, like this:
tb_product
id | active | name | value | ...
tb_config
max_product | ...
What I'd like to do is something like this
SELECT
a.name, a.value
FROM
tb_product a,
tb_config b
WHERE a.active = 1
LIMIT b.max_product
But I'm getting errors like #1327 - Undeclared variable: b. Is there a way to achieve this result?
Because currently what I'm doing is doing another query to get just the max_product value and then use it as php variable to limit the results, like this:
$limit = "SELECT max_product FROM tb_config";
SELECT name, value FROM tb_product WHERE ativo = 1 LIMIT $limit
Maybe....
SELECT a.name
, a.value
FROM tb_product a
CROSS JOIN (SELECT #Limit:=(SELECT max_product from tb_config))
WHERE a.active = 1
LIMIT #Limit
With help from #ENargit's answer in Variable LIMIT Clause in MySQL, you can do it using a row count variable.
Assuming the following schema:
CREATE TABLE
tb_product
(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(10),
`value` VARCHAR(10)
);
INSERT INTO
`tb_product`
(`name`, `value`)
VALUES
('Name1','Value1'),
('Name2','Value2'),
('Name3','Value3'),
('Name4','Value4'),
('Name5','Value5'),
('Name6','Value6'),
('Name7','Value7'),
('Name8','Value8'),
('Name9','Value9'),
('Name10','Value10');
CREATE TABLE
`tbl_config`
(
id INT PRIMARY KEY AUTO_INCREMENT,
`type` VARCHAR(10),
`value` INT
);
INSERT INTO
`tbl_config`
(`type`,`value`)
VALUES
('something',10),
('maxrows',7);
You can reference the config table with a subquery:
SELECT * FROM (
SELECT
tb_product.*,
#rownum := #rownum + 1 AS RowNum
FROM tb_product,
(SELECT #rownum := 0) AS CounterTbl
) AS DataTbl
WHERE
RowNum <= (
SELECT
`value`
FROM
`tbl_config`
WHERE
`type` = 'maxrows'
);
Gives you the first 7 rows (according to the config value). You can obviously extend this to do sorting etc.
SQLFiddle: http://www.sqlfiddle.com/#!9/f789e4/2

Get two previous and next rows data from current id SQL PHP

i have a table with database and i want get two data before current id and get two data after current id.
primary_key id
1 345
2 356
3 400
4 102
5 210
6 190
Case:
If current id defined 400, the results as before is 356 & 345 and
after is 102 & 210
If current id defined 210, the results as before is 102 & 400 and
after is 190
If current id defined 356, the results as before is 345 and
after is 400 & 102
If current id defined 345, the results as before is NULL and
after is 356 & 400
If current id defined 190, the results as before is 210 & 102 and
after is NULL
I try this SQL but not working fine,
$define_id = 400;
SELECT *
FROM table_name
WHERE (
id = IFNULL(
(
SELECT MIN(id)
FROM table_name
WHERE id > $define_id
), 0 )
OR id = IFNULL(
(
SELECT MAX(id)
FROM table_name
WHERE id < $define_id
), 0 )
)
LIMIT 2
The code success to get before and after data, but only one before and one after. I want get result two before and two after.
Please help.
Tried with the outputs you mentioned in the question. If this is not you want please explain more clearly.
CREATE TABLE IF NOT EXISTS `docs` (
`primary_key` int(6) unsigned NOT NULL,
`id` int(3) unsigned NOT NULL,
PRIMARY KEY (`primary_key`,`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `docs` (`primary_key`, `id`) VALUES
('1', '345'),
('2', '356'),
('3', '400'),
('4', '102'),
('5', '210'),
('6', '190');
Query
(SELECT * FROM docs WHERE primary_key < (SELECT primary_key FROM docs WHERE id = 400) ORDER BY primary_key DESC LIMIT 2)
UNION ALL
(SELECT * FROM docs WHERE primary_key > (SELECT primary_key FROM docs WHERE id = 400) ORDER BY primary_key ASC LIMIT 2);
Sqlfiddle link http://sqlfiddle.com/#!9/e11c8d/2
You can do it with min and max functions, So for next
SELECT * FROM `table` WHERE id = (select min(id) from `table` where id > YOUR_ID)
And for previous:
SELECT * from `table` where id = (select max(id) from table where id < YOUR_ID)
One method uses union all for the two groups:
(select 'before' as which, t.*
from t cross join
(select primary_key from t where id = $define_id) x
where t.primary_key < x.primary_key
order by t.primary_key desc
limit 2
) union all
(select 'after' as which, t.*
from t cross join
(select primary_key from t where id = $define_id) x
where t.primary_key > x.primary_key
order by t.primary_key asc
limit 2
);

Add dynamic number of variables to WHERE clause in mysql

I have the following mySQL query:
SELECT act_id, vote_date, vote_score, 'vote' AS type
FROM votes
WHERE user_voter = '1'
I want to be able to add and user_voter to the WHERE clause based on the result of another mySQL query. For example,
SELECT user_2
FROM friends
WHERE user_1 = '1'
This will output a dynamic amount of results based on the number of matches.
So, if the second query outputs:
3
4
11
32
Then I want the first query to be:
SELECT act_id, vote_date, vote_score, 'vote' AS type
FROM votes
WHERE user_voter = '1' AND user_voter = '3' AND user_voter = '4' AND user_voter = '11' AND user_voter = '32'
Hope this makes sense!
Since I am using PHP I was thinking I might have to create a while loop and have it output the results as "user_voter = '".$user2."' "; and then append it to the SELECT query before running.
You can do a subquery inside an IN()
SELECT act_id, vote_date, vote_score, 'vote' AS type
FROM votes
WHERE user_voter IN (
SELECT user_2
FROM friends
WHERE user_1 = '1'
)

How to get unique records based on one column in mysql

I have a table in which subscription_id is used multiple times, every month a customer charged an order to be generated with same data & unique order id so there is a column 'updated_at' which also updates so I want to get only one (1) latest record from table based on subscription_id, I am using following query, but it's not working and getting old record.
SELECT *
FROM members_subscriptions
WHERE status = 'active'
GROUP BY subscription_id
ORDER BY updated_at DESC
Can any one tell me what's wrong with this query ....
You need get the MAX() of updated_at , order by runs after grouping so you need to compare with the newest date
SELECT DISTINCT *
FROM members_subscriptions
WHERE status = 'active'
AND updated_at IN(
SELECT MAX(updated_at)
FROM members_subscriptions
GROUP BY subscription_id
)
ORDER BY updated_at DESC
or
SELECT DISTINCT m.*
FROM members_subscriptions m
INNER JOIN (
SELECT subscription_id, MAX(updated_at) AS updated_at
FROM members_subscriptions GROUP BY subscription_id
) AS maxdatte USING (subscription_id, updated_at);
Assumming that each subsciption can have only unique dates in updated_at, then this query should give desired result:
SELECT *
FROM members_subscriptions
WHERE status = 'active'
AND (subscription_id, updated_at) IN(
SELECT subscription_id, MAX(updated_at)
FROM members_subscriptions
GROUP BY subscription_id
)
ORDER BY updated_at DESC
But if one subscription may have more that one same dates, then the query must use unique id to get only one record from two or more with the same date:
SELECT *
FROM members_subscriptions m
WHERE status = 'active'
AND id = (
SELECT id FROM members_subscriptions m1
WHERE m.subscription_id = m1.subscription_id
AND status = 'active'
ORDER BY updated_at DESC
LIMIT 1
)
SELECT distinct (name)
FROM members_subscriptions
WHERE status = 'active'
GROUP BY subscription_id
ORDER BY updated_at DESC
use distinct with field name you want to find
The problem with your query is that result is first being grouped and only then ordered. If you need latest result, you need to do something like this:
SELECT *
FROM members_subscriptions as main
WHERE status = `active` AND `updated_at` = (
SELECT MAX(`updated_at`) FROM members_subscriptions as sub
WHERE status='active' and main.`subscription_id` = sub.`subscription_id`
)

Mysql replace two value in one query?

BEFORE
id | cat_id | order
33 | 1 | 1
34 | 1 | 2
AFTER
id | cat_id | order
33 | 1 | 2
34 | 1 | 1
Now using 4 query
$db is wrap $mysqli for using placeholder and injection defense
get first record by id
$curr = $db->q('SELECT id,order,cat_id FROM `tbl` WHERE id`=? FOR UPDATE',
33)->fetch_assoc();
if exist first record find next record by order field
if($curr){
$next = $db->q('SELECT id,order FROM `tbl` WHERE `cat_id`=? AND
`order`>? ORDER BY `order` LIMIT 1 FOR UPDATE',
$curr['cat_id'],$curr['order']));
if exist first and second recorn change order value
if($prev['id']){
$db->q("UPDATE `tbl` SET `order`=? WHERE `id`=?",$next['order'],$curr['id']);
$db->q("UPDATE `tbl` SET `order`=? WHERE `id`=?",$curr['order'],$next['id']);
}
}
Important! Checking exist two record, lock rows for update
MySQL doesn't support update with the same table in the FROM statement. So because of this there are (select * from TBL) as t2 in inner subqueries.
Also EXISTS condition in the first CASE WHEN is to prevent update if the second record doesn't exists ("if exist first and second records change order value")
Here is a SQLfiddle example
UPDATE tbl as t1
SET `order`=
CASE WHEN id = 33
and
EXISTS (SELECT ID from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`>t1.`order`
ORDER BY `order`
LIMIT 1)
THEN
(SELECT `order` from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`>t1.`order`
ORDER BY `order`
LIMIT 1)
WHEN id <>33 THEN
(SELECT `order` from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`<t1.`order`
ORDER BY `order` DESC
LIMIT 1 )
ELSE `order`
END
where id =33
or
(SELECT ID from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`<t1.`order`
ORDER BY `order` DESC
LIMIT 1) =33
With one query it's:
UPDATE
`tbl`
SET
`order`=CASE
WHEN `order`=2 THEN 1
WHEN `order`=1 THEN 2
END;
WHERE
`order` IN (1,2)
or, for id's condition:
UPDATE
`tbl`
SET
`order`=CASE
WHEN `order`=2 THEN 1
WHEN `order`=1 THEN 2
END;
WHERE
id = $id
To swap 2 fields by row id try:
UPDATE `tbl` AS tbl1
JOIN `tbl` AS tbl2 ON ( tbl1.id = 33 AND tbl2.id = 34 )
SET
tbl1.order = tbl2.order, tbl2.order = tbl1.order
Also you can set your desired value instead of swap between 2 fileds.
If needed, you can add a where clause like below to swap where cat_id are 1 in two rows:
WHERE
tbl1.cat_id = 1 AND tbl2.cat_id = 1
Update:
If your order numbers are unique for any cat_id you can try this way:
UPDATE `tbl` AS tbl1
JOIN `tbl` AS tbl2 ON ( tbl1.order = 1 AND tbl2.order = 2 )
SET
tbl1.order = tbl2.order, tbl2.order = tbl1.order
WHERE
tbl1.cat_id = 1 AND tbl2.cat_id = 1
It works if your order field is int, Otherwise you should quote order values in query.
See the result on SQLFiddle

Categories