retrieve total number of items while using the LIMIT keyword - mysql

What I'm trying to do is returning both my queried (and limited) results as well as the total number of items in the table. Here's what I have so far.
SELECT id, name
FROM ??
WHERE
user_id = ?
LIMIT ? , ?;
SELECT COUNT(*) as total
FROM ??
WHERE
user_id = ?
;
This is two SQL queries and I was wondering how or if it's possible to combine it into one. I'd like the total to be by itself (if possible), otherwise as an attached column to each row. Or maybe what I have now is the most optimal solution.

Well, you could include the count in each row using a subquery:
SELECT
id,
name,
(SELECT COUNT(*) FROM yourTable WHERE user_id = ?) total
FROM yourTable
WHERE
user_id = ?;
But, from a separations of concerns point of view, this is probably not best practice. Instead, more typically I would expect to see two separate queries here.

SELECT SQL_CALC_FOUND_ROWS
...
LIMIT ...
SELECT FOUND_ROWS();
Reference.
Or, I would vote for the CROSS JOIN, not the subquery.

Another way to do the same using CROSS JOIN
SELECT
t1.id,
t1.[name],
t2.cnt
FROM
yourtable t1
CROSS JOIN
(
SELECT
COUNT(1) AS cnt
FROM
yourtable
WHERE
[user_id] = ?
) t2
WHERE
t1.[user_id] = ?
LIMIT
?, ?

Related

Count Distinct on multiple values within same column in SQL Aggregation

Objective:
I wanted to show the number of distinct IDs for any combination selected.
In the below example, I have data at a granular level: ID level data.
I wanted to show the number of distinct IDs for each combination.
For this, I use count distinct which will give me '1' for the below combinations.
But let's say if I wanted to find the number of IDs who made both E-commerce and Face to face transactions, in that case, if I just use this data, I would be showing the sum of E-comm and Face to face and the result would be '2' instead of '1'.
And this is not limited to Ecom/Face to face. I wanted to apply the same logic for all columns.
Please let me know if you have any other alternative approach to address this issue.
First aggregate in your table to get the distinct ids for each TranType:
SELECT TranType, COUNT(DISTINCT id) counter_distinct
FROM tablename
GROUP BY TranType
and then join to the table:
SELECT t.*, g.counter_distinct
FROM tablename t
INNER JOIN (
SELECT TranType, COUNT(DISTINCT id) counter_distinct
FROM tablename
GROUP BY TranType
) g ON g.TranType = t.TranType
Or use a correlated subquery:
SELECT t1.*,
(SELECT COUNT(DISTINCT t2.id) FROM tablename t2 WHERE t2.TranType = t1.TranType) counter_distinct
FROM tablename t1
But let's say if I wanted to find the number of IDs who made both E-commerce and Face to face transactions, in
You can get the list of ids using:
select id
from t
where tran_type in ('Ecomm', 'Face to face')
group by id
having count(distinct tran_type) = 2;
You can get the count using a subquery:
select count(*)
from (select id
from t
where tran_type in ('Ecomm', 'Face to face')
group by id
having count(distinct tran_type) = 2
) i;

Count subselect elements according to parent id

I'm having this MySQL Query
SELECT
t1.article_id,
t1.user_id,
t1.like_date,
(
SELECT
COUNT(*)
FROM liketbl t2
WHERE
t1.article_id=t2.article_id
) as totallike
FROM liketbl t1
WHERE
user_id = 1;
I need to get article id, user id and liked date in one run with the number of total entries.
Subselect is, in my opinion the easiest was to achieve this.
(Don't want to run several queries in client entviroment.
But is not working.
Don't know why, help is appreceated.
try this :
SELECT t1.article_id,
t1.user_id,
t1.like_date,
COUNT(*) as totallike
FROM liketbl t1 inner join liketbl t2 on t1.article_id=t2.article_id
WHERE user_id = 1
group by t1.article_id,t1.user_id,t1.like_date;
My guess is that you need to filter on user_id = 1 in the subquery to get what you expect.
The where only operates on the outer select.
This should work
SELECT
t1.article_id,
t1.user_id,
t1.like_date,
count(SELECT * FROM liketbl t2 WHERE
t1.article_id=t2.article_id ) as totallike
FROM liketbl t1
WHERE
user_id = 1;
Scalar Subqueries tend to be the worst case, it's usually more efficient to rewrite them.
Depending on the number of rows in both tables this is another approach using a Derived Table:
SELECT
t1.article_id
,t1.user_id
.t1.like_date
,t2.totallike
FROM liketbl t1
JOIN
(
SELECT
article_id
,COUNT(*) AS totallike
FROM liketbl
GROUP BY article_id
) AS t2
ON t1.article_id=t2.article_id
WHERE
user_id = 1;

mysql optimization: select a non previously selected random pair of different values from a column of unique values

What would be the most efficient way to select a non previously selected pair of different random values from a column of unique (non repeated) values?
My current approach is (keeping every pair of values already associated in a separate "mytable_associations" table):
SELECT * FROM
(
SELECT id,count(*) AS associations_count FROM mytable
INNER JOIN mytable_associations
WHERE (myvalue=myvalue1 OR myvalue=myvalue2)
GROUP BY myvalue
HAVING associations_count<(SELECT count(*) FROM mytable)-1
ORDER BY rand() limit 1
) mytable1
LEFT JOIN
(SELECT myvalue AS myvalue2 FROM mytable) mytable2
ON mytable1.myvalue1<>mytable2.myvalue2
WHERE
(
SELECT myvalue1 FROM mytable_associations
WHERE
myvalue1=mytable1.myvalue1 AND myvalue2=mytable2.myvalue2
OR
myvalue1=mytable2.myvalue2 AND myvalue2=mytable1.myvalue1
) IS NULL;
(And then of course update mytable_associations with this new association)
Which, as you can see, could hugely benefit from some optimization.
(Sorry about the poor indentation in the code, I really don't know how to indent mysql commands).
Can you help me?
(P.S. This is my first question ever posted here: Sure I'm doing lots of things wrong and I'd understand the consequent flaming, but please don't be too hard on me ;) )
Any solution involving order by rand() is going to be inefficient. For alternatives, see:
My answer to Selecting random rows with MySQL
Jan Kneschke on Order by RAND()
To exclude numbers you've already picked, here's how I'd do it (this is pseudocode):
$c1 = SELECT COUNT(DISTINCT myvalue) FROM mytable
$c2 = SELECT COUNT(*) FROM mytable_associations
$offset = ROUND( RAND() * ($c1 * ($c1-1) - $c2) )
SELECT v.* FROM (
SELECT LEAST(m1.myvalue,my2.myvalue) AS myvalue1,
GREATEST(m1.myvalue,my2.myvalue) AS myvalue2
FROM (SELECT DISTINCT myvalue FROM mytable) AS m1
INNER JOIN (SELECT DISTINCT myvalue FROM mytable) AS m2
ON m1.myvalue <> m2.myvalue
) AS v
LEFT OUTER JOIN mytable_associations AS a USING (myvalue1,myvalue2)
WHERE a.myvalue1 IS NULL
LIMIT 1 OFFSET $offset
By ensuring that myvalue1 < myvalue2, and storing them in that order in mytable_associations, you can simplify the join.

How to count the number of entries in two selects?

Semi-newbyism ahead: I need to do two selects and count the number of items in both of them. Here's a bad example of what I thought would work --
sum(
select count(*) as count1 from users where name = 'John'
union
select count(*) as count1 from users where name = 'Mary'
) as theCount
(This is, as I said, a BAD example, since I could obviously write this as a single select with an appropriate WHERE clause. In what I really have to do, the two things I have to do are such that I can't do them as a single select (or, at least, I haven't yet found a way to do them as a single select).
Anyway, I think what I'm trying to do is clear: the select-union-select bit returns a column containing the counts of the two selects; that part works fine. I thought that wrapping them in a SUM() would get me what I wanted, but it's throwing a syntax error. The right thing is probably trivial, but I just don't see it. Any thoughts out there? Thanks!
For generic selects that you can't necessarily write with one where:
SELECT sum(count1) as totalcount FROM (
select count(*) as count1 from users where name = 'John'
union all
select count(*) as count1 from users where name = 'Mary'
) as theCount
select count(*) as count1 from users where name in ('John','Mary')
This is another alternative
select ( select count(*) as count1 from users where name = 'John')
+
( select count(*) as count1 from users where name = 'Mary') as total
Another possible solution:
select
sum(if(name='John',1,0)) as tot_John,
sum(if(name='Mary',1,0)) as tot_Mary,
sum(if(name in ('John','Mary'),1,0)) as total
from users

Can "Distinct" key Word be used twice in a single Select Query?

Can "Distinct" key Word be used twice in a single Select Query? like wise:
select DISTINCT(trackid), DISTINCT(table_name)
from jos_audittrail
where live = 0 AND operation = UPDATE
Thanks
No, By Default Distinct works on all the columns you are selecting.
eg.
select DISTINCT trackid, table_name
from jos_audittrail
where live = 0 AND operation = UPDATE
This will select all distinct trackid and table name combination
EDIT
For retrieving distinct records other than this you can use the answer given by davek. It will work.
You can use group by to do this work as group by is being applied on both the columns being provided so no aggregate function is needed.
SELECT trackid, table_name FROM jos_audittrail
WHERE live = 0 AND operation = 'UPDATE'
GROUP BY trackid, tablename
select trackid
, table_name
, count(*)
from jos_audittrail
where live = 0 AND operation = UPDATE
group by trackid, table_name
order by trackid, table_name
would give you distinct combinations of the two.
No you can't use that, it will throw an error, but there are other alternatives where you can get your desired results.
the easiest way to find this it is to just run the query. i just tried, and it didn't work.
however, you can use two columns in a GROUP BY -- just do this:
select trackid, table_name from jos_audittrail where live = 0 and operation = 'UPDATE' group by trackid, tablename