how to count rows by first letter? - mysql

a noob question here!
I wrote this query, but the "group by" is very stupid...
so, how can I correct this?
SELECT
COUNT(*) AS total,
'x' as test
FROM
contents
WHERE name LIKE 'C%'
GROUP BY
test
ORDER BY id ASC
different solutions and info about performances are welcome ( maybe using DISTINCT? )
thanks in advance!

This should perform as well as any other option -
SELECT
LEFT(name, 1) AS first_letter,
COUNT(*) AS total
FROM contents
GROUP BY first_letter
If you want to run this query for a single letter at a time you can add the WHERE clause and drop the GROUP BY -
SELECT COUNT(*) AS total
FROM contents
WHERE name LIKE 'a%'

Let's dissect your query:
SELECT
COUNT(*) AS total,
'x' as test <-- Why?
FROM <-- Bad formatting.
contents
WHERE name LIKE 'C%'
GROUP BY
test <-- Removing 'x' and the whole GROUP BY has the same effect.
ORDER BY id ASC <-- The result only contains one row - nothing to sort.
So the query that returns one row with one field, containing the number of rows whose name begins with 'C' would look like this:
SELECT COUNT(*)
FROM contents
WHERE name LIKE 'C%'
Having an index whose leading edge is name would ensure good performance. To understand why, take a look at the Anatomy of an SQL Index.

should give you everything in case you want it
SELECT
COUNT(*) AS total,
test
FROM
(SELECT substring(name,1,1) as test
from contents) t
GROUP BY test

Related

match results generated by SQL WHERE IN CLAUSE

let's see I have a simple table like this:
name id
tom 1
jerry 2
... ...
And from the outside, I got a list contains the names (tom, jerry, kettie...)
I am trying to use WHERE IN clause to retrieve the id based on the name list.
I can do
SELECT id FROM mySimpleTable where name in ('tom','jerry','kettie');
So just iterate the name list and generate the contents in the parentheses.
This works, but the results is not in the input order, for example, the input is tom, jerry, kettie, the expected the result is 1,2,3, however, the output actually could be in any order.
Then how can I modify the SQL clause to make sure I get my input and output matched so that I can do the following process accrordingly. I heard JOIN may help in this situation.
SELECT id
FROM mySimpleTable
where name in ('tom','jerry','kettie')
order by field(name, 'tom','jerry','kettie')
I heard JOIN may help in this situation.
Yes it can help:
SELECT m.id
FROM mySimpleTable m
JOIN (
SELECT 'tom' AS name, 1 AS orderNum
UNION ALL
SELECT 'jerry' AS name, 2 AS orderNum
UNION ALL
SELECT 'kettie' AS name, 3 AS orderNum
) AS sub
ON m.name = sub.name
ORDER BY sub.orderNum ASC;
SqlFiddleDemo
This solution can be also used in different RDBMS. field is MySQL specific.
How it works:
Create derived table/subquery with values you need to check and ordering column
JOIN will return only rows that correspond each other based on name
ORDER BY column you've added in subquery
just select id,name from table_a where name in ('tom','jerry','happy') , you will have the combination of the input name and output id.
this entirely depends on where you're getting the list for your "in" clause.
if it's from somewhere on the outside, you probably should first turn the list into a temp table, adding an id column that indicates the order (see this answer for a start on how to do that) - and then do an inner join with it.
I did try to run your SQL query, and me for one did get the resultant output in the same order as that of the input. Well, but still it isn't necessary it would happen the same way every time, so the best way to arrange your output in a particular hierarchy is to use the ORDER BY clause. The syntax would be:
SELECT column_name
FROM table_name
WHERE conditions
ORDER BY column_name;
So in your case, the query would read as:
SELECT id
FROM mysimpletable
WHERE name
IN('tom','jerry','kettie'....)
ORDER BY id;
You can get more help with MySQL concepts here for further information.
Select
id
from mySimpleTable
where name in ('tom','jerry','kettie')
Order by id

How to isolate a tuple from sql ordering while ordering the rest?

I searched for an answer here and didn't find one closer to my question.
I have the following situation: I need to display a person first and then show the rest in ascending order. All the people from the same table. I tried UNION but after that, the SQL seems to mix everything again.
I have tried this:
select name from people where name = 'John'
UNION
select name from people order by name
Since UNION does not select duplicated values. But in the end, it mixed up every result and did not show in the correct order that should be:
John
Ana
Bruce
What am I doing wrong?
You need to use order by to get what you want. In MySQL, this is pretty easy:
select name
from people
order by (name = 'John') desc, name
Results sets (like tables) represent unordered sets in SQL. The only way to impose an order is to use order by. The order by at the end of a union/union all query applies to the entire query.
As an aside, your code would come close to working if you used union all -- which is much preferred over union. The union operation does additional work to remove duplicates. In this case, that reorders the results, a convenient reminder that you can only depend on the order of results when you use order by.
Also you can use UNION ALL in a derived table
SELECT name
FROM
(
SELECT 1 AS Row_Id, name
FROM people
WHERE name = 'John'
UNION ALL
SELECT 2 AS Row_Id, name
FROM people
) t
ORDER BY Row_Id

MySQL - SELECT all columns WHERE one column is DISTINCT

I'm very sorry if the question seems too basic.
I've surfed entire Internet and StackOverflow for a finished solution, and did not find anything that I can understand, and can't write it myself, so have to ask it here.
I have a MySQL database.
It has a table named "posted".
It has 8 columns.
I need to output this result:
SELECT DISTINCT link FROM posted WHERE ad='$key' ORDER BY day, month
But I need not only the "link" column, but also other columns for this row.
Like for every row returned with this query I also need to know its "id" in the table, "day" and "month" values etc.
Please tell me what should I read to make it, or how to make it.
Please keep it as simple as possible, as I'm not an expert in MySQL.
Edit:
I tried this:
SELECT DISTINCT link,id,day,month FROM posted WHERE ad='$key' ORDER BY day, month
It doesn't work. It returns too many rows. Say there are 10 rows with same links, but different day/month/id. This script will return all 10, and I want only the first one (for this link).
The problem comes from instinctively believing that DISTINCT is a local pre-modifier for a column.
Hence, you "should" be able to type
XXbadXX SELECT col1, DISTINCT col2 FROM mytable XXbadXX
and have it return unique values for col2. Sadly, no. DISTINCT is actually a global post-modifier for SELECT, that is, as opposed to SELECT ALL (returning all answers) it is SELECT DISTINCT (returning all unique answers). So a single DISTINCT acts on ALL the columns that you give it.
This makes it real hard to use DISTINCT on a single column, while getting the other columns, without doing major extremely ugly backflips.
The correct answer is to use a GROUP BY on the columns that you want to have unique answers: SELECT col1, col2 FROM mytable GROUP BY col2 will give you arbitrary unique col2 rows, with their col1 data as well.
I tried this:
SELECT DISTINCT link,id,day,month FROM posted
WHERE ad='$key' ORDER BY day, month
It doesn't work. It returns too many rows. Say there are 10 rows with
same links, but different day/month/id. This script will return all
10, and I want only the first one (for this link).
What you're asking doesn't make sense.
Either you want the distinct value of all of link, id, day, month, or you need to find a criterion to choose which of the values of id, day, month you want to use, if you just want at most one distinct value of link.
Otherwise, what you're after is similar to MySQL's hidden columns in GROUP BY/HAVING statements, which is non-standard SQL, and can actually be quite confusing.
You could in fact use a GROUP BY link if it made sense to pick any row for a given link value.
Alternatively, you could use a sub-select to pick the row with the minimal id for a each link value (as described in this answer):
SELECT link, id, day, month FROM posted
WHERE (link, id) IN
(SELECT link, MIN(id) FROM posted ad='$key' GROUP BY link)
SELECT Id, Link, Day, Month FROM Posted
WHERE Id IN(
SELECT Min(Id) FROM Posted GROUP BY Link)
SELECT OTHER_COLUMNS FROM posted WHERE link in (
SELECT DISTINCT link FROM posted WHERE ad='$key' )
ORDER BY day, month
If what your asking is to only show rows that have 1 link for them then you can use the following:
SELECT * FROM posted WHERE link NOT IN
(SELECT link FROM posted GROUP BY link HAVING COUNT(LINK) > 1)
Again this is assuming that you want to cut out anything that has a duplicate link.
I think the best solution would be to do a subquery and then join that to the table. The sub query would return the primary key of the table. Here is an example:
select *
from (
SELECT row_number() over(partition by link order by day, month) row_id
, *
FROM posted
WHERE ad='$key'
) x
where x.row_id = 1
What this does is the row_number function puts a numerical sequence partitioned by each distinct link that results in the query.
By taking only those row_numbers that = 1, then you only return 1 row for each link.
The way you change what link gets marked "1" is through the order-by clause in the row_number function.
Hope this helps.
SELECT DISTINCT link,id,day,month FROM posted WHERE ad='$key' ORDER BY day, month
OR
SELECT link,id,day,month FROM posted WHERE ad='$key' ORDER BY day, month
If you want all columns where link is unique:
SELECT * FROM posted WHERE link in
(SELECT link FROM posted WHERE ad='$key' GROUP BY link);
What you want is the following:
SELECT DISTINCT * FROM posted WHERE ad='$key' GROUP BY link ORDER BY day, month
if there are 4 rows for example where link is the same, it will pick only one (I asume the first one).
I had a similar problem, maybe that help someone, for example - table with 3 columns
SELECT * FROM DataTable WHERE Data_text = 'test' GROUP BY Data_Name ORDER BY Data_Name ASC
or
SELECT Data_Id, Data_Text, Data_Name FROM DataTable WHERE Data_text = 'test' GROUP BY Data_Name ORDER BY Data_Name ASC
Two ways work for me.
SELECT a.* FROM orders a INNER JOIN (SELECT course,MAX(id) as id FROM orders WHERE admission_id=".$id." GROUP BY course ) AS b ON a.course = b.course AND a.id = b.id
With the Above Query you will get unique records with where condition
In MySQL you can simply use "group by". Below will select ALL, with a DISTINCT "col"
SELECT *
FROM tbl
GROUP BY col
Select the datecolumn of month so that u can get only one row per link, e.g.:
select link, min(datecolumn) from posted WHERE ad='$key' ORDER BY day, month
Good luck............
Or
u if you have date column as timestamp convert the format to date and perform distinct on link so that you can get distinct link values based on date instead datetime

How to get count of rows returned from nested and WHERE IN used query in MySQL?

SELECT kullaniciNick,
kullaniciAdi,
kullaniciSoyadi
FROM panelkullanicilari
WHERE id IN
(SELECT user_id
FROM proje_ekip
WHERE proje_id=11)
ORDER BY kullaniciSoyadi
at the query i need the count of rows to check if it is over 6 or less.
When i used the COUNT(*) i got an error message. That said it must used with GROUP BY.
Thank you.
Try this:
SELECT kullaniciNick,
kullaniciAdi,
kullaniciSoyadi,
count(*) -- Added this line
FROM panelkullanicilari
WHERE id IN
(SELECT user_id
FROM proje_ekip
WHERE proje_id=11)
GROUP BY 1,2,3 -- Added this line
ORDER BY kullaniciSoyadi
You can't have a result, and it's size in one query.
Use 2 queries. First one will give you the size of result and second one will be the result. The First query, should be like this:
SELECT count(*)
FROM panelkullanicilari
WHERE id IN
(SELECT user_id
FROM proje_ekip
WHERE proje_id=11)
the second one , is just like the query you wrote above.

How to perform COUNT() or COUNT(*)

I have a list of tags in a database.
Ex:
villan
hero
spiderman
superman
superman
I wanted to obtain a sorted list of the tag names in ascending order and the number of times the unique tag appeared in the database. I wrote this code:
Ex:
SELECT hashtag.tag_name
, COUNT( * ) AS number
FROM hashtag
GROUP BY hashtag.tag_name
ORDER BY hashtag.tag_name ASC
This yields the correct result:
hero , 1
spiderman , 1
superman , 2
villan , 1
How can I obtain the full COUNT of this entire list. The answer should be 4 in this case because there are naturally 4 rows. I can't seem to get a correct COUNT() without the statement failing.
Thanks so much for the help! :)
SELECT COUNT(DISTINCT `tag_name`) FROM `hashtag`
Use COUNT DISTINCT(hashtag.tag_name) -- it can't go in the same SELECT you have (except with a UNION of course), but on a SELECT of its own (or an appropriate UNION) it will give the result you want.
i am not sure about the query in my-sql but this one works fine with oracle.
SELECT hashtag.tag_name, count(*) FROM hashtag GROUP BY cube(hashtag.tag_name)
To do it exactly as you're describing (to obtain the full count of the resulting list), you'd want to take a count of the results, like:
SELECT COUNT(*) AS uniquetags
FROM (SELECT hashtag.tag_name, COUNT( * ) AS number
FROM hashtag GROUP BY hashtag.tag_name
ORDER BY hashtag.tag_name ASC)
Of course the ORDER BY clause is unnecessary and gets swallowed by the outer aggregate COUNT, as does the inner COUNT.
Additionally, as a few people have pointed out, the shortcut to this is a COUNT DISTINCT, as in:
SELECT COUNT(DISTINCT hashtag.tag_name)
FROM hashtag
This may or may not use indexes more efficiently, depending on whether it realizes it doesn't have to count everything or not. Someone with more knowledge, please feel free to comment (or just try a couple EXPLAINs).