Select all records with same column value after search - mysql

I have table called 'forms' that looks like this
ID
entry_id
content
1
1
text
2
1
rand txt
3
1
another rand txt
4
2
new entry
I need to search this table based on content (eg. SELECT * FROM forms WHERE content LIKE 'text';), and if the record is found, all other records with same entry_id need to be selected.
For example, if the record with ID 1 is found with search query, records with ID 2 and 3 should be selected as well since they belong to the same entry.

SELECT t2.*
FROM forms t1
JOIN forms t2 USING (entry_id)
WHERE t1.content LIKE 'text';
Remember - LIKE without pattern symbols searches direct matching only (i.e. is equal to =).

One method uses exists:
select f.*
from forms f
where exists (select 1
from forms f2
where f2.id = f.id and
f.content like 'text'
);
You can also use window functions:
select f.*
from (select f.*,
sum( f.content like 'text' ) over (partition by id) as num_text
from forms f
) f
where num_text > 0;

Try:
SELECT *
FROM forms AS f1 INNER JOIN forms AS f2 ON f1.entry_id = f2.entry_id
WHERE f1.content LIKE 'text'

Your query should be like this. You can use nested query.
SELECT * FROM forms
WHERE entry_id IN
(SELECT entry_id FROM forms WHERE content LIKE '%text%')

Related

SQL Multiple Left joins

I have a table called documents with a row called Nigel Harding
DOCUMENTS
id | label
24 | Nigel Harding
He has been tagged with two other documents one with an ID of 1 & 12 that table is called document tags
DOCUMENT_TAGS
id | label | Document_id
1 | TAG A | 24
12 | TAG B | 24
I am trying to create a query where I can find one result where Nigel Harding will appear once if searching for the tags 1 AND 12 but i'm having no luck.
I figured out the query for searching one tag id but i'm trying to do the query for both tags.
SELECT documents.id
FROM documents
LEFT JOIN documents_tags
ON documents.id=documents_tags.document_id
WHERE documents_tags.tag_id = 1 ORDER BY documents.label
I understand why adding...
AND documents_tags.tag_id = 12
...to the end of that will not work but i'm not sure what i need to do get the correct query display my one result as my understanding of SQL is very basic.
If I understand your question, you're just lacking IN and DISTINCT:
SELECT DISTINCT documents.id
FROM documents
LEFT JOIN documents_tags
ON documents.id=documents_tags.document_id
WHERE documents_tags.tag_id IN (1, 12) ORDER BY documents.label
Using IN you'll be getting documents for any of the tag ids specified, and using DISTINCT you'll make sure to get each document id only once.
EDIT: Since you're ordering by documents.label, I'm guessing that's what you want displayed. Don't forget you can change your SELECT statement to:
SELECT DISTINCT documents.label
or even to:
SELECT DISTINCT documents.id, documents.label
I think the most flexible way to approach this type of problem is to use aggregation with a having clause. Here is one example:
SELECT dt.document_id
FROM documents_tags dt
GROUP BY dt.document_id
HAVING sum(dt.tag_id = 1) > 0 and
sum(dt.tag_id = 12) > 0;
Each condition in the having clause counts the number of document tags that are 1 (or 12) and the filter passes only when both are found. You could also write this as:
SELECT dt.document_id
FROM documents_tags dt
WHERE dt.tag_id in (1, 12)
GROUP BY dt.document_id
HAVING count(distinct dt.tag_id) = 2;
Another way to accomplish this (adjusted to search by tag label which I think is your goal, if not just replace dt.Label = 'etc' with dt.ID = etc):
SELECT documents.id
FROM documents d
WHERE
exists (select dt.id from documents_tags dt
where dt.document_id = d.document_id and dt.label = 'TAG A')
AND
exists (select dt.id from documents_tags dt
where dt.document_id = d.document_id and dt.label = 'TAG B')
one WHERE word is enough:
SELECT documents.id
FROM documents
LEFT JOIN documents_tags
ON documents.id=documents_tags.document_id
WHERE (documents_tags.tag_id = 1 OR documents_tags.tag_id = 12) ORDER BY documents.label
alternatively, if you are going to work with n different tags and don't want to add OR documents_tags.tag_id = x ever time you can use IN operator
SELECT documents.id
FROM documents
LEFT JOIN documents_tags
ON documents.id=documents_tags.document_id
WHERE documents_tags.tag_id IN(1,12) ORDER BY documents.label
It sounds like you're trying to aggregate the results when you search for multiple document tags, so you should use GROUP BY, which is for grouping multiple rows into one row:
SELECT documents.id
FROM documents
LEFT JOIN documents_tags ON documents.id = documents_tags.document_id
WHERE documents_tags.tag_id IN (1, 12)
GROUP BY documents.id
This will give you one row for each document that matches the given tag ids. And you can generalize to any list of tag ids by adding to the list without too much pain. You could even add a COUNT(*) to the select statement to find out how many tag ids where matched for the given document.

Select records that match a field, but order them by a different field

my tables look like this:
tags: id, name, description
tag_relations: tag, item
item references the id of another table and tag references the id of the tags table.
So I'm trying to select the most used tags:
SELECT t.*, COUNT(r.item) AS item_count
FROM tag_relations as r
INNER JOIN tags as t ON r.tag = t.id
GROUP BY t.id
ORDER BY item_count
which works, but if I add
WHERE t.id = ?
the item_count is always 1...
Is there any way I could still have the global tag count with a select statement that selects only 1 tag or a specific set of tags?
Sql fiddle at
http://www.sqlfiddle.com/#!2/ba97d/1
SELECT name,count(item) as counter_item
FROM tag_relations
INNER JOIN tags ON
tag_relations.tag =tags.id
order by counter_item
the line
where tags.id=1
Can be added if needed
I don't have access to MySQL, but I do have access to Microsoft SQLServer. I realize your tags specify mysql. Even so, the query you presented fails in SQLServer with error
Msg 8120, Level 16, State 1, Line 1
Column 'tags.name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
... because the select t.* is not included in the group by clause.
Anyways, to address your specific question you can derive a global number while still selecting a specific record using cross join...
select
t.*
, vTagRelations.GlobalCountOfTagRelations
, vTags.GlobalCountOfTags
from
tags t
cross join (select
count(tag_relations.tag) as GlobalCountOfTagRelations
from
tag_relations) vTagRelations
cross join (select
count(tags.id) as GlobalCountOfTags
from
tags) vTags
where
t.id = 2
In SQLite, using sub-query:
SELECT *, (SELECT COUNT() FROM tag_relations WHERE tag=tags.id) AS item_count FROM tags WHERE id=?;

Is there any way to send a column value from outer query to inner sub query?

'Discussions' table schema
title description desid replyto upvote downvote views
browser used a1 none 1 1 12
- bad topic b2 a1 2 3 14
sql database a3 none 4 5 34
- crome b4 a3 3 4 12
The above table has two types of content types Main Topics and Comments. Unique content identifier 'desid' used to identify that its a main topic or a comment. 'desid' starts with 'a' for Main Topic and for comment 'desid' starts with 'b'. For comment 'replyto' is the 'desid' of main topic to which this comment is associated.
I like to find out the list of the top main topics that are arranged on the basis of (upvote+downvote+visits+number of comments to it) addition. The following query gives top topics list in order of (upvote+downvote+visits)
select * with highest number of upvote+downvote+views by query
select *
from [DB_user1212].[dbo].[discussions]
where desid like 'a%'
order by (upvote+downvote+visited) desc
For (comments+upvote+downvote+views ) i tried
select *
from [DB_user1212].[dbo].[discussions]
where desid like 'a%'
order by (select count(*)
from [DB_user1212].[dbo].[discussions]
where replyto = desid )+upvote+downvote+visited) desc
but it didn't work . Because its not possible to send desid from outer query to innner subquery. Please tell me how to solve this. Please note that I want solution in query language only.
You need to use table aliases:
select *
from [DB_user1212].[dbo].[discussions] d1 --alias
where desid like 'a%'
order by (select count(*)
from [DB_user1212].[dbo].[discussions] d2
where d2.replyto = d1.desid )+upvote+downvote+visited) desc
Now, in the subquery, you can refer to the outer tables by alias (here, d1). I also added d2, which is not necessary here, but it can be useful to be explicit in subqueries.
I think this will work:) let me know, please.
WITH x AS
(
select count(*) numberofcomments, replyto
from [DB_user1212].[dbo].[discussions]
GROUP BY replyto
)
select [DB_user1212].[dbo].[discussions].*
from [DB_user1212].[dbo].[discussions]
inner JOIN x
ON [DB_user1212].[dbo].[discussions].desid = x.replyto
where desid like 'a%'
ORDER BY (numberofcomments+upvote+downvote+visited)

looking for a slight variant of GROUP BY

I have a table like so:
id attr
1 A
2 A
3 C
4 C
5 D
6 F
I want a count of all the A's B's (but not the C's D's, etc..) Note that my table has zero B's.
So I want a command like this:
SELECT count(attr=A, attr=B) FROM table;
or this:
SELECT count(*) FROM table GROUP_BY attr IN (A, B);
and get:
attr count
A 2
B 0
My actual table has about a thousand attrs. I want to do a group_by-ish thing on maybe a hundred or so of them. It's important that i get the count of zero for certain attrs and that i can correlate the attr to the count.
I know this is a basic question and I'm not surprised if this has been asked before. I searched.. But my apologies anyway..
SELECT T.attr,
COUNT(Y.id)
FROM (SELECT 'A' AS attr
UNION ALL
SELECT 'B') AS T
LEFT JOIN YourTable Y
ON Y.attr = T.attr
GROUP BY T.attr
This should work for you.
SELECT T.Attr,Count(A.ID)
FROM (
SELECT CONVERT('A',char) AS Attr
UNION
SELECT CONVERT('B',char) AS Attr
) AS T
LEFT JOIN MyTable AS A
ON T.Attr=MyTable.Attr
GROUP BY T.Attr
ORDER BY T.Attr;
The Convert part may not be necessary but was necessary in my testing.

Way to find rows with a same ID and only keep one row

I have a working query that will return some results(records) from my database, like:
123|John Williams|IL|M|06/01/2011|ACTIVE
124|Mary Haque|NY|F|TERMINATED|06/30/2011
124|Mary Haque|NY|F|07/01/2011|ACTIVE
125|Alex Chan|VA|07/01/2011|ACTIVE
126|Rob Kreb|VA|TERMINATED|06/20/2011
As you can see, the result is simply a list of customer records, while the last two fields indicate whether the member is active or terminated and associated active/terminated date.
The complication now is, as you can see for member with ID 124 (Mary Haque), she has two records, and for this kind of two-record customer, I only want to keep the row where the member is active while totally ignore her terminated history. So for example, the desired output for the above should be:
123|John Williams|IL|M|06/01/2011|ACTIVE
124|Mary Haque|NY|F|07/01/2011|ACTIVE
125|Alex Chan|VA|07/01/2011|ACTIVE
126|Rob Kreb|VA|TERMINATED|06/20/2011
as you can see, now Mary Haque only has her active information on the result. The above result is generate by a SQL "Select" query, but I couldn't simply append a "WHERE status=ACTIVE" to this query because I still want to keep the members that only has ONE record like Rob Kreb above even though he is terminated. I only want the filtering for TERMINATED member record to take place when a certain member has two records.
FYI, my current query looks like this:
SELECT * FROM customer_change WHERE CUSTOMER_LOGIN NOT IN(SELECT CUSTOMER_LOGIN FROM customer_full WHERE CUSTOMER_LOGIN IS NOT NULL)
UNION
SELECT * FROM customer_change WHERE CUSTOMER_POINTS=0 AND CUSTOMER_LOGIN NOT IN(SELECT CUSTOMER_LOGIN FROM customer_full WHERE CUSTOMER_POINTS=0 AND CUSTOMER_LOGIN IS NOT NULL)
Thanks for the help in advance!
colX and colY are the last 2 columns of the query:
SELECT *
FROM (your_UNION_query) AS p
WHERE NOT ( colX = 'TERMINATED'
AND EXISTS
( SELECT *
FROM (your_UNION_query) AS q
WHERE q.id = p.id
AND q.colY = 'ACTIVE'
)
)
Something like this will do the trick:
DELETE
FROM tablename
WHERE tablename.status = 'TERMINATED'
AND tablename.id IN(SELECT
id
FROM (SELECT
t.id
FROM tablename t
GROUP BY t.id
HAVING COUNT(t.id) > 1) AS T1)
Assuming that id is the field refering to 124,125, etc.