SQL - How to find index - mysql

I am using MySQL 5.0.
I have table with following structure and data.
CREATE TABLE `test`
(
`text1` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `test` (`text1`)
VALUES ('ABC'), ('PQR'), ('XYZ'), ('LMN');
I want to display following output:
Index Text
1 ABC
2 LMN
3 PQR
4 XYZ
In table structure, I don't want to create any new column.
How can I write a SQL query or a stored procedure to accomplish this?
Thanks in advance.

This will not answer your question, but you should really reconsider what you are asking for.
There are no index. You can print a number for each row in your application code, but that number would be meaningless. Without an actual index field in your table, you can't be sure what each number means. For example, if two users remove row "2" simultaneously, both LMN and PQR may be deleted. This is unexpected and dangerous.
You are also not guaranteed to get the rows in the same order each time you do a query if you lack an ORDER BY clause.

SET #row=0;
SELECT #row := #row + 1 AS Index, text1 as Text FROM test;

select #rownum:=#rownum+1 Id, text1
from test, (SELECT #rownum:=0) r
order by text

Related

MySQL INSERT ... SELECT ... never ends, CPU at max

I need to delete duplicates from a table while keeping one item. Since I cannot delete from a table while accessing this very same table in a subquery inside the where-statement, i decided to store my affected IDs in a temporary table:
create temporary my_temp_table (
id int not null
) engine memory;
and then insert IDs using a select:
insert into my_temp_table
-- select query works
select
id
from
-- innodb
table_with_duplicates
where
hash_code in (
select
hash_code
from
table_with_duplicates
group by
hash_code
having
count(id) > 1
)
and date_created < '2015-01-01'
;
Later I want to use these IDs to delete them:
delete from table_with_duplicates
where id in (
select id from my_temp_table
)
;
Just executing the select part of the insert statement works fine. Adding the insert part, however, causes 1 CPU core to go up to 100% and the query seems to never end. Nothing is inserted.
On my dev environment, table_with_duplicates contains about 20000 rows with 1 duplicate.
Any ideas?
EDIT:
Thank you for your answers. I have tried a select distinct(... approach, which didn't help much. Maybe I've used in the wrong place/subselect. Played around with it quite a lot already. To clarify, I have something like this:
ID date_created hash_code
1 2013-06-06 ABCDEFGH <-- delete this one
2 2013-08-08 HGFEDCBA
3 2015-11-11 ABCDEFGH <-- keep this one
Well, I chose different approach to solve this problem. I've written a small PHP command-line script that fetches all my IDs into an array and then executes a DELETE, using all IDs as ....
"delete from table_with_duplicates where id in (".explode(',' $arrIDs).")";
Having about 9000 affected rows and this (hopefully) being a one-time action, this worked for me.
I also played around with
SET SESSION optimizer_search_depth = 1;
but had no luck either.

Is there an easy SELECT-Statement that creates an empty set?

Is there an easy and simple way to create a result table that has specified columns but zero rows? In set theory this is called an empty set, but since relational databases use multidimensional sets the term doesn't fit perfectly. I have tried these two queries, but both deliver exactly one row and not zero rows:
SELECT '' AS ID;
SELECT null AS ID;
But what I want is the same result as this query:
SELECT ID FROM sometable WHERE false;
I'm searching for a more elegant way because I don't want to have a table involved, so the query is independent from any database scheme. Also a generic query might be a bit faster (not that it would matter for such a query).
SELECT "ID" LIMIT 0;
Without any real tables.
Do note that most (My)SQL clients simply will display "Empty set". However, it actually does what you want:
create table test.test_table
select "ID" limit 0;
show create table test.test_table\G
Table: test_table
Create Table: CREATE TABLE `test_table` (
`ID` varchar(2) character set latin1 NOT NULL default ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
SELECT * FROM (SELECT NULL AS ID) AS x WHERE 1 = 0
You can use the DUAL pseudo-table.
SELECT whatever FROM DUAL WHERE 1 = 0
Check the documentation (look for the DUAL section).

Delete duplicated mysql rows with no primary key

Hi i have a mysql table without primary key and i need to delete the duplicated rows. how can i do so?
user_id category_id
1 2
1 3
1 4
1 2
2 2
2 3
2 2
CREATE TABLE temp SELECT DISTINCT * FROM tablename;
ALTER TABLE tablename RENAME junk;
ALTER TABLE temp RENAME tablename;
Since you cannot differentiate 2 identical rows, you cannot delete just one of them. The way you need to think about it is like this:
insert into new_better_table
select user_id, category_id from old_table group by user_id, category_id
It's possible to use a dirty flag with default value 1 and copy only single records with the flag set to 0, then simply remove all dirty records. This way you don't need another table.
Assuming you already created a dirty flag with default value 1:
insert into mytable
select fld1,fld2,fldN,0 as dirty
from mytable
group by duplicate_field
Then you can just delete dirty records:
delete from mytable where dirty = 1
Don't forget to remove the dirty flag. You're done.
The select distinct * solution proposed in another answer will not work in cases where your rows contain null values. A better solution that also prevents future duplicates from appearing in my_table in the first place is as follows:
create table no_dupes like my_table;
alter table no_dupes add unique index(unique_column,or_columns);
insert ignore into no_dupes select * from my_table;
rename table my_table to junk, no_dupes to my_table;

Assigning row rank numbers

I have a database. I want to update a column of it. The column should contain unique integer numbers in ascending order according to alphabetical order of another column.
Sorry not clear maybe, I want to have integer numbers like this:
1 ACC 501
2 BCC 501
3 GCC 601
4 FCC 601
Is there a reasonably simple way of setting this rank/order with mysql or sql query?
What you need is a ranking function which is not supported by MySQL at the moment. However, you can simulate them like so:
Set #rownum := 0;
Select rnk, SomeCode, SomeNum
From (
Select #rownum := #rownum + 1 As rnk, SomeCode, SomeNum
From MyTable
Order By SomeCode Asc
) As Z
Create another table that has the same schema as your original table, plus the new column. The new column should be an autonumber. Do an INSERT...SELECT into that table. The new column will be filled out with the values you want.
Like what Alex said, you want to create a new table like
CREATE TABLE newTable(
#Table definition from current table,
id INT NOT NULL AUTO_INCREMENT
);
And then insert with
INSERT INTO newTable
SELECT * FROM oldTable
ORDER BY orderColumn;
I think you can quickly do the create table with
CREATE TABLE newTable LIKE oldTable;
ALTER TABLE newTable ADD COLUMN id INT NOT NULL AUTO_INCREMENT;

MySQL INSERT Using Subquery with COUNT() on the Same Table

I'm having trouble getting an INSERT query to execute properly, and I can't seem to find anything on Google or Stack Overflow that solves this particular issue.
I'm trying to create a simple table for featured entries, where the entry_id is saved to the table along with it's current order.
My desired output is this:
If the featured table currently has these three entries:
featured_id entry_id featured_order
1 27 0
2 54 1
4 23 2
I want the next entry to save with featured_order=3.
I'm trying to get the following query to work with no luck:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured`)
)
The error I'm getting is: You can't specify target table 'featured' for update in FROM clause.
Can anyone help with a solution that gets the count without causing an error?
Thanks in advance!
Here is a cool thing: MySQL's INSERT . . . SELECT:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
SELECT 200, COUNT(*) + 1
FROM `featured`
No subquery required.
#Bohemian has a good point:
Better to use max(featured_order) + 1 if you use this approach
So a better query would probably be:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
SELECT 200, MAX(`featured_order`) + 1
FROM `featured`
His trigger method describe in his answer is also a good way to accomplish what you want.
The potential problem with query 1 is if you ever delete a row the rank will be thrown off, and you'll have a duplicate in featured_order. With the second query this is not a problem, but you will have gaps, just as if you were using an auto-increment column.
If you absolutely must have an order with no gaps the best solution I know of is to run this series of queries:
SET #pos:=0;
DROP TABLE IF EXISTS temp1;
CREATE TEMPORARY TABLE temp1 LIKE featured;
ALTER TABLE featured ORDER BY featured_order ASC;
INSERT INTO temp1 (featured_id, entry_id, featured_order)
SELECT featured_id, entry_id, #pos:=#pos+1 FROM words;
UPDATE featured
JOIN temp1 ON featured.featured_id = temp1.featured_id
SET featured.rank = temp1.rank;
DROP TABLE temp1;
Whenever you delete a row
Use a trigger:
drop trigger if exists featured_insert_trigger;
delimiter //
create trigger featured_insert_trigger before insert on featured
for each row
begin
set new.featured_order = ifnull((select max(featured_order) from featured), -1) + 1;
end; //
delimiter ;
Now your inserts look like this:
insert into featured (entry_id) values (200);
featured_order will be set to the highest featured_order value plus one. This caters for rows being deleted/updated and always guarantee uniqueness.
The ifnull is there in case there are no rows in the table, in which case the first value will be zero.
This code has been tested as works correctly.
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured` F1)
)
Correction is just adding "F1" table alias.
This standard sql solution works fine on various dbms (not only mysql)
I also suggest an improvement over:
SELECT COUNT(*) +1 (Problem: if some row gets deleted you may collide with existing index)
SELECT MAX(featured_order)+1 (Problem: the first insert with empty table gets error)
SELECT (COALESCE(MAX(featured_order), 0)+1) (no Problem)
You have to simpley use alias that will solve the problem :
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured` as f1)
)
From the MySQL manual regarding subqueries:
Another restriction is that currently you cannot modify a table and select from the same table in a subquery.
Perhaps an alias or a join (otherwise useless) in the subquery would help here.
EDIT: It turns out that there's a work-around. The work-around is described http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/.