Currently we have have following combined different data i.e one with comma separated and one without comma separated in same table.
#1
id | values
------------
1 | 1,2,3
2 | 4,5,6
3 | 7,8,9
4 | 1
5 | 2
6 | 3
7 | 4
8 | 5
Let's say I want to search value 1 from the table and count it. Which is the most optimal way of querying for such kind of data structure ? Is it using :
WHERE value =
WHERE value LIKE
WHERE value IN
Or Do I need to change my database and have all values to be in same format ?
Any help or advice on best practices would be appreciated.
Never store multiple values in one column!
Please normalize your data. That makes it way easier to query and it is also faster and can make use of indexes.
I agree that normalizing your data is the way to go to get optimal performance. But not changing the schemma, you can't really use = because you may have multiple numbers. One way to count the number of occurrences for 1 in those comma separated values is using FIND_IN_SET():
SELECT SUM(CASE
WHEN FIND_IN_SET(1, `values`)
THEN 1
ELSE 0
END) AS count1
FROM tab1
sqlfiddle demo
Related
$query = SubjectUser::where('user_id', Auth::id())->select('subjectlist_name')->get();
The query above produces these results from Table One:
[{"subjectlist_name":football},{"subjectlist_name":cricket},
{"subjectlist_name":tennis},{"subjectlist_name":f1}]
I have another table that looks like this:
Table Two
ID|second_user_id|topic |mark(enum '0','1')
1 | 2 |football |0
2 | 2 |tennis |0
3 | 2 |f1 |0
4 | 2 |Rugby |0
I now want to iterate through my query result and check for matching topics and mark those that do match so that my second table looks like this:
Table Two
ID|second_user_id|topic |mark(enum '0','1')
1 | 2 |football |1
2 | 2 |tennis |1
3 | 2 |f1 |1
4 | 2 |Rugby |0
The problem I have is that i'm unsure how many subjectlist_name's to expect hence wondering whether there is an elegant way to solve this problem?
It does depend a bit on the load you're expecting. If this is for a rare usecase and you do not have heavy traffic on your site, then I would probably consider using an SQL query like this:
update second_table_name set mark = 1 and second_user_id= <??> where topic in (select subjectlist_name from first table where user_id=<??>)
this should generally do what you want although this will not be performant. If this happens more than once every 10 seconds (and/or you've got some serious other traffic going on), then you might want to iterate in chunks over table one and do update clauses with
... where topic in ("f1", "...")
however, in that case, please note, you should be having some indexes going on for doing those operations.
Also please consider that "unsure how many subjectlist_names to expect": just check out an approximate number: is it possible that there could be above 1000? if no, then you will probably not need to chunk anyways. This will make the code simpler and easier to understand for everyone.
I have two table
one table is alldata ( here info_id is a text field data inserted using php )
=================
id | info_id
=================
1 | 2, 3, 5, 9
2 |
=================
second table is info
=================
id | name
=================
1 | one
2 | two
3 | three
4 | four
5 | five
6 | six
7 | seven
9 | eight
9 | nine
=================
now I want to select list of data from table two where data id will be matched with table one first item info_id data
my query is
SELECT i.* FROM `info` as i,`alldata` as a where i.id IN(a.info_id) and a.id=1
my query works but select only one item from table two.But there are multiple matched.
You have a very poor database design. First, storing numeric ids as strings is a bad idea -- numbers should be stored as numbers. Second, SQL offers this great data structure for storing lists. It is called a table, not a string.
You should really have a junction table, one one row per id and info_id.
That said, sometimes we a struck with substandard data structure. MySQL offers support for this. You can use:
SELECT i.*
FROM `info` i JOIN
`alldata` a
ON FIND_IN_SET(i.id, REPLACE(a.info_id, ', ', ',') ) > 0
WHERE a.id = 1;
You should also learn to use proper, explicit join syntax. If you use this method, instead of fixing the database design, you are not allowed to complain about performance. MySQL cannot take advantage of things like indexes to improve the performance of this type of query.
I please need some help:
I have this database, which has this fields with their respect values:
agency_id | hostess_id
3 | 12-4-6
5 | 19-4-7
1 | 1
In hostess_id are stored all hostesses ids that are associated with that agency_id but separated with a "-"
Well, i login as a hostess, and i have the id=4
I need to retrieve all the agency_id which contain the id=4 , i can't do this with like operator.. i tried to do it by saving the hostess_id row to an array, then implode it, but i can't resolve it like this.
Please, please any idea?
You should change your database design. What you are describing is a typical N:N relation
Agencies:
agency_id | name
3 | Miami
5 | Annapolis
1 | New York
Hosteses
Hostes_id | name
4 | Helen
12 | May
19 | June
AgencyHostes
Hostes_id | agency_id
4 | 1
4 | 3
4 | 5
12 | 1
12 | 3
19 | 1
First, let me say that I absolutely agree with #JvdBerg on that this is terrible database design that needs to be normalized.
Let's think for a minute though, that you have no way of changing the database layout and that you must solve this with SQL, an inefficient but working solution would be
select agency_id from tablename where
hostess_id LIKE '4-%' OR
hostess_id LIKE '%-4-%' OR
hostess_id LIKE '%-4'
if you were searching for all agencies with hostess id 4. I build this on sqlfiddle to illustrate more thoroughly http://sqlfiddle.com/#!2/09a52/1
Mind though, that this SQL statement is hard to optimize since an index structure for substring matching is rarely employed. For very short id lists it will work okay though. If you have ANY chance at changing the table structure, normalize your schema like #JvdBerg suggested and look up database design and normal forms on google.
i have a table in which a row contains following data. So i need to compare data among themselves and show which data has maximum count.for ex. my table has following fruits name. So i need to compare these fruits among themselves and show max fruit count first.
s.no | field1 |
1 |apple,orange,pineapple |
2 |apple,pineapple,strawberry,grapes|
3 |apple,grapes, |
4 |orange,mango |
i.e apple comes first,grapes second,pineapple third and so on. and these datas are entered dynamically, so whatever the values is entered dynamically it needs to compare among themselves and get max count
Great question.
This is a classical bad outcome of not having the data normalized.
I recommend you to read about Database Normalization, normalize your tables and see after that how easy it is to do this with simple SQL queries
If you need to run queries on column field 1, then why not consider normalization ? Otherwise it might keep on getting complex and dirty in future.
Your current table will look like this (for serianl number 1 only), Pk can be an autoincrement primary key.
Pk | s.no |fruitId|
1 | 1 |1 |
2 | 1 |2 |
3 | 1 |3 |
Your New Table of Fruits
PK |fruitName |
1 |Apple |
2 |Orange |
3 |Pineapple |
This also helps you to avoid redundancy.
Quick solution would be counting the amount of fruits where you insert/update the row and add a fruitCount column. You can then use this column to order by.
Zohaib has to correct solution though - if you have the time and possibility for such changes. And I definitely suggest you to read Tudor's link!
Hey,
I'm having a sorting issue. I have the rows:
32
16
8
semifinals
finals
that i need to be sorted like that. The problem is they don't always appear in that order. Right now I'm using: ORDER BY ABS(roundOf) DESC and it's comming out:
32
16
8
finals
semifinals
Thanks.
There is no way to do this without storing an order number with that data. The words semifinals and finals do not hold any order data comparable to the numbers of course. Store this in an array in the order you need it or if it's stored in a relational db, use an order column.
Possible db table:
order | name | numberOfPlayers
1 | finals | 2
2 | semis | 4
...
Array:
$rounds = array[1] = 'finals';
etc.
rename your finals and semifinals into numbers.