MySQL : Return random value from each column - mysql

Note: This might be a strange question.
I have a table containing first name and last name, which schema as follow (table name: random_names):
id INT PRIMARY, AUTO INCREMENT
first_name VARCHAR(100) NOT NULL
last_name VARCHAR(100) NOT NULL
I would like to use a query to fetch a random value from first_name and last_name. Currently I use 2 queries to fetch the value:
SELECT first_name FROM random_names ORDER BY rand()
SELECT last_name FROM random_names ORDER BY rand()
But I wish I can output a list of random results in 1 result output. What did I miss ?

select
(select first_name from random_names order by rand() limit 1) as random_first_name,
(select last_name from random_names order by rand() limit 1) as random_last_name;
though for tables of any size it is much faster if you programmatically determine the number of entries and pick a random offset for each column:
select
(select first_name from random_names order by rand() limit $first_name_offset,1) as random_first_name,
(select last_name from random_names order by rand() limit $last_name_offset,1) as random_last_name;
where the offsets are a random number from 0 to one less than the result of select count(*) from random_names.
Followup question:
but how about list out result count equal to the number of values in original table? (just like shuffle the data in the table)
I'd do that like this:
create temporary table rand_last (id int(11) primary key auto_increment, last_name text) select last_name from random_names order by rand();
create temporary table rand_first (id int(11) primary key auto_increment, first_name text) select first_name from random_names order by rand();
select first_name, last_name from rand_first inner join rand_last using (id);
or possibly like this (assuming random_names has an 'id' primary key):
create temporary table rand_one (id int(11) primary key auto_increment, random_names_id int(11)) select id random_names_id from random_names order by rand();
create temporary table rand_two (id int(11) primary key auto_increment, random_names_id int(11)) select id random_names_id from random_names order by rand();
select rand_first.first_name, rand_last.last_name from rand_one inner join rand_two using (id) inner join random_names rand_first on rand_one.random_names_id=rand_first.id inner join random_names rand_last on rand_two.random_names_id=rand_last.id;

You can get all possible pairs of first_name and last_name in random order by following query:
select *
from (select first_name from random_names) a,
(select last_name from random_names) b
order by rand();

You can also do like this-
SELECT first_name, last_name FROM random_names ORDER BY rand()
OR
SELECT concat(first_name," ",last_name) fullname FROM random_names ORDER BY rand()

Related

How to select last created record in a group by clause in mysql?

I am using mysql 8.0.23
I have three tables, chats, chat_users and chat_messages
I want to select the chat_id, the last message (with maximum createdAt date for a particular group. Said in other words, the message order by created_at desc within the group), from_user_id values for all the chats where user with id 1 is a member.
The tables sql and DDLs is are like below
create table chats
(
id int unsigned auto_increment primary key,
created_at timestamp default CURRENT_TIMESTAMP not null
);
create table if not exists chat_users
(
id int unsigned auto_increment
primary key,
chat_id int unsigned not null,
user_id int unsigned not null,
constraint chat_users_user_id_chat_id_unique
unique (user_id, chat_id),
constraint chat_users_chat_id_foreign
foreign key (chat_id) references chats (id)
);
create index chat_users_chat_id_index
on chat_users (chat_id);
create index chat_users_user_id_index
on chat_users (user_id);
create table chat_messages
(
id int unsigned auto_increment primary key,
chat_id int unsigned not null,
from_user_id int unsigned not null,
content varchar(500) collate utf8mb4_unicode_ci not null,
created_at timestamp default CURRENT_TIMESTAMP not null constraint chat_messages_chat_id_foreign
foreign key (chat_id) references chats (id),
);
create index chat_messages_chat_id_index
on chat_messages (chat_id);
create index chat_messages_from_user_id_index
on chat_messages (from_user_id);
The query that I tried so far and is not working properly is
SET #userId = 1;
select
c.id as chat_id,
content,
chm.from_user_id
from chat_users
inner join chats c on chat_users.chat_id = c.id
inner join chat_messages chm on c.id = chm.chat_id
where chat_users.user_id = #userId
group by c.id
order by c.id desc, max(chm.created_at) desc
My query above does not return the content field from the last created message, although I am trying to order by max(chm.created_at) desc. This order by after group by clause is executed after the grouping I think and not within the items from the group..
I know that I can probably select in the select statement the max date but I want to select last content value within the group not select max(ch.created_at) as last_created_at_msg_within_group
I don't know how to select the content field from the item that has the highest chm.created_at from within the group that I do by grouping with c.id
Example test data
chats
1 2021-07-23 20:51:01
2 2021-07-23 20:51:01
3 2021-07-23 20:51:01
chats_users
1 1 1
2 1 2
3 2 1
4 2 2
5 3 1
6 3 2
chat_messages
1 1 1 lastmsg 2021-07-28 21:50:31
1 1 2 themsg 2021-07-23 20:51:01
The logic in this case should return
chat_id content from_user_id
1 lastmsg 1
PS:
Before posting here I did my homework and studied similar questions in the forum, but they were trying to get last inserted row from a group and were not like mine.
Here's what I came up with, for a solution for MySQL 8.0 with window functions:
select * from (
select
c.id as chat_id,
content,
chm.from_user_id,
chm.created_at,
row_number() over (partition by c.id order by chm.created_at desc) as rownum
from chat_users
inner join chats c on chat_users.chat_id = c.id
inner join chat_messages chm on c.id = chm.chat_id
where chat_users.user_id = #userId
) as t
where rownum = 1;

Order a Table in MySql without sendtime

How can I query to find the most recent message in a table, when the values in the column sendTime are all null?
I have tried.
SELECT `from`
,MAX(column) AS most_recent_message
FROM table
GROUP BY `from`
if you have an auto increment primary key, then you can find the maximum primary key belongs to which column.
SELECT * FROM your_table WHERE id = (SELECT MAX(id) FROM your_table);

How can I get the most recent rows from two different, unrelated tables, and merge them into one result set?

I have two different tables with their schema given below:
Table1:
COLUMN_NAME COLUMN_TYPE
campaign_id varchar(50)
subscriber_id varchar(50)
message varchar(21000)
log_time datetime
log_type varchar(50)
level varchar(50)
campaign_name varchar(500)
Table2:
COLUMN_NAME COLUMN_TYPE
guid varchar(100)
sid varchar(100)
url varchar(2500)
ip varchar(20)
is_new varchar(20)
ref varchar(2500)
user_agent varchar(255)
stats_time datetime
country varchar(50)
region varchar(50)
city varchar(50)
city_lat_long varchar(50)
email varchar(100)
I need a table which is a merge of these two tables(not all the columns) and the rows should sorted based on time (which is log_time in Table1 and stats_time in Table2). There is no relation between these two tables.
The columns which I need from Table1 are
campaign_id
subscriber_id
message
log_time
log_type
campaign_name
and the columns which I need from Table2 are:
url
stats_time
email
Can I get more optimised solution?
Query:
SELECT url, ip, stats_time, email, campaign_id, subscriber_id, campaign_name, log_time, log_type, time from
(
( SELECT url,ip,stats_time,email,NULL AS campaign_id,NULL AS subscriber_id ,NULL AS campaign_name,NULL AS log_time,NULL AS log_type, NULL AS message, UNIX_TIMESTAMP(stats_time) AS time FROM Tabel2 AS Table2Alias WHERE URL !='' AND EMAIL != '') Order by stats_time desc Limit 100
UNION ALL
( SELECT NULL AS url,NULL AS ip,NULL AS stats_time,NULL AS email,campaign_id,subscriber_id,campaign_name,log_time,log_type,message,UNIX_TIMESTAMP(log_time) AS time FROM Table1 AS Table1Alias WHERE (log_type='x1' OR log_type='x2' OR log_type='x3' OR log_type='x4') order by log_time desc Limit 100)
)
as ResultTable order by time desc
Select the top Limit + Offset records from each table, UNION the results, then select from the UNION.
So if user is viewing page 5, and there are 20 items per page, you will be selecting top 100 from each table, performing UNION, then selecting 20 records from result.
Some pseudocode for you -
SELECT
/* columns you want */
FROM
(
SELECT
/* columns you want */
FROM
/* Table1 */
ORDER BY
/* Date DESC */
LIMIT 20
UNION ALL
SELECT
/* columns you want */
FROM
/* Table2 */
ORDER BY
/* Date DESC */
LIMIT 20
)
ORDER BY
/* Date DESC */
LIMIT 20

Return the number of rows expected for a group by query

I would like to get the number of rows returned from a mysql query that uses group by.
table
CREATE TABLE IF NOT EXISTS TestRunSteps (
`idTestRunSteps` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`idUsersExecBy` VARCHAR(10) NULL ,
`LastExecUserIPV4` INT UNSIGNED NULL ,
PRIMARY KEY (`idTestRunSteps`);
SELECT count(*)
from proj1_db.TestRunSteps
group by idUsersExecBy,LastExecUserIPV4
returns
3,000002,3232236222
1,000003,3232236222
5,000004,3232236222
What I would like to have is a simple 3 - for 3 rows. Please tell me how
The number of groups is the number of distinct combinations of the columns grouped by. The query that returns that number is:
select count(distinct idUsersExecBy, LastExecUserIPV4)
from proj1_db.TestRunSteps
select count(*)
from
(SELECT count(*)
from proj1_db.TestRunSteps
group by idUsersExecBy,LastExecUserIPV4) as temp

Counting TINYINT values in MySQL

The table structure is like this:
actions: int(10)
unlock: tinyint(1)
user_id: int(20)
name: varchar(50)
I have such query:
SELECT SUM(actions) AS "sum_actions", SUM(unlock) AS "sum_unlock", user_id, name
FROM mytable AS `Results` WHERE user_id != 0 GROUP BY user_id
ORDER BY sum_actions DESC LIMIT 0,300
This gives #1064 - You have an error in your SQL syntax error.
When I remove SUM(unlock) AS "sum_unlock" then query works. So I thought that it is not possible to summing TINYINTs. So I changed to COUNT(unlock) as "count_unlock" but this didn't help. I don't want to change "unlock" table to INT because it only has boolean values. How can I count the unlock table with summing for each user_id ?
unlock is a reserved word. Try this:
SELECT SUM(actions) AS "sum_actions", SUM(`unlock`) AS "sum_unlock", user_id, name
FROM mytable AS `Results`
WHERE user_id != 0
GROUP BY user_id
ORDER BY sum_actions DESC
LIMIT 0,300
Here is a list of reserved words.
You can try SUM(CAST(unlock AS INT)) to count as if the column was an INT column without actually changing it to be an INT column:
SELECT
SUM(actions) AS "sum_actions",
SUM(CAST(unlock AS INT)) AS "sum_unlock",
user_id,
name
FROM
mytable AS `Results`
WHERE
user_id != 0
GROUP BY
user_id,
name
ORDER BY
sum_actions DESC
LIMIT 0,300