Sql serialize columns into one record for search - mysql

I would like to create a search feature which looks in multiple tables and columns and return the main idea. For example:
(This is a very simplified scenario, and the real tables have way more columns in which I would like to search)
table 'lead':
id | name | created
1 | john | 1/1/2014
2 | jack | 2/1/2014
table 'notes':
id | lead_id | created | note
1 | 1 | 1/1/2014 | lead added
2 | 1 | 1/2/2014 | some change occurred
3 | 2 | 2/1/2014 | lead added
4 | 2 | 2/2/2014 | some updates
I would like to provide for example the string "2014" which would return lead.id 1,2
Or look for "updates" which would return lead.id 2.
I can either run a join every time the search is performed, or somehow create a view which looks like this:
id | text
1 | john 1/1/2014 1/1/2014 lead added 1/2/2014 some change occurred
2 | jack 2/1/2014 2/1/2014 lead added 2/2/2014 some updates
This way, the search would be in one table and provide a fairly quick results, the "work" is updating the records per id every time tables 'notes' is updated.
I know a view is the best way to do this, but I am not clear on how to serialize a join result into one textual column. Of course it is fairly easy with php (or any back end script) but I was wondering if this can be done in a manner similar to when a view is constantly updated.
Thank you for your assistance.

Use GROUP BY and GROUP_CONCAT functions, somethink like this:
SELECT n.lead_id, CONCAT(l.name, " ", l.created, " ",GROUP_CONCAT(CONCAT(n.`created`," ",n.`note`), " ")) as text
FROM notes n
JOIN lead l ON l.id = n.lead_id
GROUP BY n.`lead_id`
ORDER BY n.`created` DESC
Inner CONCAT forms submessage 1/1/2014 lead added, GROUP CONCAT joins then and the outer CONCAT forms result message john 1/1/2014 1/1/2014 lead added 1/2/2014 some change occurred
Here is SQL Fiddle example

Related

Select two values from two different tables

I have two tables, they look like this:
Table 1
==========================
id_tab1 | worker | number
==========================
1 | Adam | 123123
Table 2
==========================
id_tab2 | worker | number
==========================
1 | Adam | 123456
They both don't have anything in common. Sometimes worker might be in both of them and I want to count every row from both tables and show them like:
===============================================
worker | count_numbers_tab1 | count_numbers_tab2
===============================================
Adam | 1 | 1
I tried with INNER JOIN but it shows weird numbers.
EDIT 1:
As with Abhilekh answer I ended up with following query(real example):
SELECT druga_klasa.pracownik, COUNT(druga_klasa.numer_zlecenia), COUNT(zlewy_zlomy.numer_zlecenia) FROM druga_klasa
FULL JOIN zlewy_zlomy on druga_klasa.pracownik=zlewy_zlomy.pracownik
GROUP BY pracownik;
and thats how real tables looks like
and I've got an error saying
Unknown column druga_klasa.pracownik in field list.
What do you mean by they both don't have anything in common?
SELECT table1.worker, COUNT(table1.number), COUNT(table2.number) FROM table1
INNER JOIN table 2 on table1.worker=table2.worker
GROUP BY worker;
But this will only work if the column worker is common to both.

How to structure a MySQL query to join with an exclusion

In short; we are trying to return certain results from one table based on second level criteria of another table.
I have a number of source data tables,
So:
Table DataA:
data_id | columns | stuff....
-----------------------------
1 | here | etc.
2 | here | poop
3 | here | etc.
Table DataB:
data_id | columnz | various....
-----------------------------
1 | there | you
2 | there | get
3 | there | the
4 | there | idea.
Table DataC:
data_id | column_s | others....
-----------------------------
1 | where | you
2 | where | get
3 | where | the
4 | where | idea.
Table DataD: etc. There are more and more will be added ongoing
And a relational table of visits, where there are "visits" to some of these other data rows in these other tables above.
Each of the above tables holds very different sets of data.
The way this is currently structured is like this:
Visits Table:
visit_id | reference | ref_id | visit_data | columns | notes
-------------------------------------------------------------
1 | DataC | 2 | some data | etc. | so this is a reference
| | | | | to a visit to row id
| | | | | 2 on table DataC
2 | DataC | 3 | some data | etc. | ...
3 | DataB | 4 | more data | etc. | so this is a reference
| | | | | to a visit to row id
| | | | | 4 on table DataB
4 | DataA | 1 | more data | etc. | etc. etc.
5 | DataA | 2 | more data | etc. | you get the idea
Now we currently list the visits by various user given criteria, such as visit date.
however the user can also choose which tables (ie data types) they want to view, so a user has to tick a box to show they want data from DataA table, and DataC table but not DataB, for example.
The SQL we currently have works like this; the column list in the IN conditional is dynamically generated from user choices:
SELECT visit_id,columns, visit_data, notes
FROM visits
WHERE visit_date < :maxDate AND visits.reference IN ('DataA','DataC')
The Issue:
Now, we need to go a step beyond this and list the visits by a sub-criteria of one of the "Data" tables,
So for example, DataA table has a reference to something else, so now the client wants to list all visits to numerous reference types, and IF the type is DataA then to only count the visits if the data in that table fits a value.
For example:
List all visits to DataB and all visits to DataA where DataA.stuff = poop
The way we currently work this is a secondary SQL on the results of the first visit listing, exampled above. This works but is always returning the full table of DataA when we only want to return a subset of DataA but we can't be exclusive about it outside of DataA.
We can't use LEFT JOIN because that doesn't trim the results as needed, we can't use exclusionary joins (RIGHT / INNER) because that then removes anything from DataC or any other table,
We can't find a way to add queries to the WHERE because again, that would loose any data from any other table that is not DataA.
What we kind of need is a JOIN within an IF/CASE clause.
Pseudo SQL:
SELECT visit_id,columns, visit_data, notes
FROM visits
IF(visits.reference = 'DataA')
INNER JOIN DataA ON visits.ref_id = DataA.id AND DataA.stuff = 'poop'
ENDIF
WHERE visit_date < 2020-12-06 AND visits.reference IN ('DataA','DataC')
All criteria in the WHERE clause are set by the user, none are static (This includes the DataA.stuff criteria too).
So with the above example the output would be:
visit_id | reference | ref_id | visit_data | columns | notes
-------------------------------------------------------------
1 | DataC | 2 | some data | etc. |
2 | DataC | 3 | some data | etc. |
5 | DataA | 1 | more data | etc. |
We can't use Union because the different Data tables contain lots of different details.
Questions:
There may be a very straightforward answer to this but I can't see it,
How can we approach trying to achieve this sort of partial exclusivity?
I suspect that our overarching architecture structure here could be improved (the system complexity has grown organically over a number of years). If so, what could be a better way of building this?
What we kind of need is a JOIN within an IF/CASE clause.
Well, you should know that's not possible in SQL.
Think of this analogy to function calls in a conventional programming language. You're essentially asking for something like:
What we need is a function call that calls a different function depending on the value you pass as a parameter.
As if you could do this:
call $somefunction(argument);
And which $somefunction you call would be determined by the function called, depending on the value of argument. This doesn't make any sense in any programming language.
It is similar in SQL — the tables and columns are fixed at the time the query is parsed. Rows of data are not read until the query is executed. Therefore one can't change the tables depending on the rows executed.
The simplest answer would be that you must run more than one query:
SELECT visit_id,columns, visit_data, notes
FROM visits
INNER JOIN DataA ON visits.ref_id = DataA.id AND DataA.stuff = 'poop'
WHERE visit_date < 2020-12-06 AND visits.reference = 'DataA';
SELECT visit_id,columns, visit_data, notes
FROM visits
WHERE visit_date < 2020-12-06 AND visits.reference = 'DataC';
Not every task must be done in one SQL query. If it's too complex or difficult to combine two tasks into one query, then leave them separate and write code in the client application to combine the results.

MYSQL query fetching DATA from two table using IN method one as composition of multiple data

I have two tables
one as td_job which has these structure
|---------|-----------|---------------|----------------|
| job_id | job_title | job_skill | job_desc |
|------------------------------------------------------|
| 1 | Job 1 | 1,2 | |
|------------------------------------------------------|
| 2 | Job 2 | 1,3 | |
|------------------------------------------------------|
The other Table is td_skill which is this one
|---------|-----------|--------------|
|skill_id |skill_title| skill_slug |
|---------------------|--------------|
| 1 | PHP | 1-PHP |
|---------------------|--------------|
| 2 | JQuery | 2-JQuery |
|---------------------|--------------|
now the job_skill in td_job is actualy the list of skill_id from td_skill
that means the job_id 1 has two skills associated with it, skill_id 1 and skill_id 2
Now I am writing a query which is this one
SELECT * FROM td_job,td_skill
WHERE td_skill.skill_id IN (SELECT td_job.job_skill FROM td_job)
AND td_skill.skill_slug LIKE '%$job_param%'
Now when the $job_param is PHP it returns one row, but if $job_param is JQuery it returns empty row.
I want to know where is the error.
The error is that you are storing a list of id's in a column rather than in an association/junction table. You should have another table, JobSkills with one row per job/skill combination.
The second and third problems are that you don't seem to understand how joins work nor how in with a subquery works. In any case, the query that you seem to want is more like:
SELECT *
FROM td_job j join
td_skill s
on find_in_set(s.skill_id, j.job_skill) > 0 and
s.skill_slug LIKE '%$job_param%';
Very bad database design. You should fix that if you can.

MySQL query to compare content of one column with title of other column

I know the title makes no sense at first glance. But here's the situation: the DB table is named 'teams'. In it, there are a bunch of columns for positions in a soccer team (gk1, def1, def2, ... , st2). Each column is type VARCHAR and contains a player's name. There is also a column named 'captain'. The content of that column (not the most fortunate solution) is not the name of the captain, but rather the position.
So if the content of 'st1' is Zlatan Ibrahimovic and he's the captain, then the content of 'captain' is the string 'st1', and not the string 'Zlatan Ibrahimovic'.
Now, I need to write a query which gets a row form the 'teams' table, but only if the captain is Zlatan Ibrahimovic. Note that at this point I don't know if he plays st1, st2 or some other position. So I need to use just the name in the query, to check if the position he plays on is set as captain. Logically, it would look like:
if(Zlatan is captain)
get row content
In MySQL, the if condition would actually be the 'where' clause. But is there a way to write it?
$query="select * from teams where ???";
The "Teams" table structure is:
-----------------------------------------------------------------
| gk1 | def1 | def2 | ... | st2 | captain |
-----------------------------------------------------------------
| player1 | player2 | player3 | ... | playerN | captainPosition |
-----------------------------------------------------------------
Whith all fields being of VARCHAR type.
Because the content of the captain column is the position and not the name, and you want to choose based on the position, this is trivial.
$query="select * from teams where captain='st1'";
Revised following question edit:
Your database design doesn't allow this to be done very efficiently. You are looking at a query like
SELECT * FROM teams WHERE
(gk1='Zlatan' AND captain='gk1') OR
(de1='Zlatan' AND captain='de1') OR
...
The design mandates this sort of query for many functions: how you can find the team which a particular player plays for without searching every position? [Actually you could do that by finding the name in a concatenation of all the positions, but it's still not very efficient or flexible]
A better solution would be to normalise your data so you had a single table showing which player was playing where:
Situation
Team | Player | Posn | Capt
-----+--------+------+------
1 | 12 | 1 | 0
1 | 11 | 2 | 1
1 | 13 | 10 | 0
...with other tables which allow you to identify the Team, Player and Postion referenced here. There would need to be some referential checks to ensure that each team had only one captain, and only plays one goalkeeper, etc.
You could then easily see that the captain of Team 1 is Player 11 who plays in position 2; or find the team (if any) for which player 11 is captain.
SELECT Name FROM Teams
WHERE Situation.Team = Teams.id
AND Situation.Capt = 1
AND Situation.Player = Players.id
AND Players.Name = 'Zlatan';
A refinement on that idea might be
Situation
Team | Player | Posn | Capt | Playing
-----+--------+------+------+--------
1 | 12 | 1 | 0 | 1
1 | 11 | 2 | 1 | 1
1 | 13 | 10 | 0 | 0
1 | 78 | 1 | 0 | 0
...so that you could have two players who are goalkeepers (for example) but only field of them.
Redesigning the database may be a lot of work; but it's nowhere near as complicated or troublesome as using your existing design. And you will find that the performance is better if you don't need to use inefficient queries.
By what have you exposed, you just need to put the two conditions and check if the query returned 1 record. If it returns no records, he is not the captain:
SELECT *
FROM Teams
WHERE name = 'Zlatan Ibrahimovic' AND position = 'st1';

MySQL - COUNT before INSERT in one query

Hey all, I am looking for a way to query my database table only once in order to add an item and also to check what last item count was so that i can use the next number.
strSQL = "SELECT * FROM productr"
After that code above, i add a few product values to a record like so:
ID | Product | Price | Description | Qty | DateSold | gcCode
--------------------------------------------------------------------------
5 | The Name 1 | 5.22 | Description 1 | 2 | 09/15/10 | na
6 | The Name 2 | 15.55 | Description 2 | 1 | 09/15/10 | 05648755
7 | The Name 3 | 1.10 | Description 3 | 1 | 09/15/10 | na
8 | The Name 4 | 0.24 | Description 4 | 21 | 09/15/10 | 658140
i need to count how many times it sees gcCode <> 'na' so that i can add a 1 so it will be unique. Currently i do not know how to do this without opening another database inside this one and doing something like this:
strSQL2 = "SELECT COUNT(gcCode) as gcCount FROM productr WHERE gcCode <> 'na'
But like i said above, i do not want to have to open another database query just to get a count.
Any help would be great! Thanks! :o)
There's no need to do everything in one query. If you're using InnoDB as a storage engine, you could wrap your COUNT query and your INSERT command in a single transaction to guarantee atomicity.
In addition, you should probably use NULL instead of na for fields with unknown or missing values.
They're two queries; one is a subset of the other which means getting what you want in a single query will be a hack I don't recommend:
SELECT p.*,
(SELECT COUNT(*)
FROM PRODUCTR
WHERE gccode != 'na') AS gcCount
FROM PRODUCTR p
This will return all the rows, as it did previously. But it will include an additional column, repeating the gcCount value for every row returned. It works, but it's redundant data...