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.
Related
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%')
I'm trying to get the correlated value in a table from a mysql query which looks like:
select min(c), d
from example
table example looks like:
c | d
----------------
'1,99', '30,99'
'5,99', '8,46'
'9,99', '14,99'
'11,79', '17,24'
'12,99', '19,44'
'15,99', '22,44'
'22,49', '34,48'
Given result:
1,99 & 34,48
Expected result:
1,99 & 30,99
What I want is the correlated value from the min(c) in this case '30,99'. How to do that?
You can do it with a sub query:
SELECT * FROM example
WHERE c = (SELECT min(c) from example)
EDIT: if there's more then 1 records the answer the condition, then you need to decide which one you wanna pick.
SELECT * FROM example
WHERE c = (SELECT min(c) from example)
ORDER BY d
LIMIT 1
This will take the one with the smallest d value.
To take the biggest, add DESC after the order by d in the query.
You need to use subquery:
select e.*
from (select min(c) as c from example) x
join example e
on x.c = e.c;
I have this query:
SELECT C.ID_PASS, C.ID_MERCE, CTRL.ESITO, M.ID_CAT, M.QTA, M.DESCRIZ,
CTRL.ID_PUNTO, CTRL.ID_ADDETTO, C.DATE_OPEN, C.DATE_CLOSE, C.NOTE
FROM CONTESTAZIONI C, CONTROLLI CTRL, FUNZIONARI F, ADDETTI A, MERCI M
WHERE A.ID=CTRL.ID_ADDETTO
AND A.ID_FUNZ=501
AND M.ID=C.ID_MERCE
AND M.ID_PASS=C.ID_PASS
AND CTRL.ESITO > 1
GROUP BY C.ID_PASS;
Why, if I don't add GROUP BY C.ID_PASS, do I get 20 rows (instead of 2).
You get a cross-product when doing joins with "," operator. You should include the IDs from all tables into your where clause!
Basically, you need to link all 5 tables together by ensuring equalities of their rows' IDs, because as noted in the comment, you have two groups of tables, but they are not linked and the resulting set thus has lots of duplicates.
GROUP BY is used to group rows together when using aggregate functions, such as SUM or COUNT.
If you had, for example, 4 records, with say 2 for each cust id, each with a value:-
CustId Spend
1 10
1 20
2 30
2 40
If you wanted to know the total of each value for each customer you would use something like:-
SELECT CustId, SUM(Spend) FROM SomeTable GROUP BY CustId
This would give you
CustId Sum(Spend)
1 30
2 70
Part of what it does is remove the duplicated rows and sum up all the values into one row.
It can be misused without an aggregate function to remove duplicates and this is what you have done. Hence 2 records instead of 20.
Note that if you have fields in the SELECT that are not in the GROUP BY variable, and which are not 100% dependent on the group by fields then the value of that field is indeterminate.
For example
CustId Spend ShopId
1 10 1
1 20 2
2 30 3
2 40 4
If you wanted to know the total of each value for each customer you would use something like:-
SELECT CustId, ShopId, SUM(Spend) FROM SomeTable GROUP BY CustId
This would give you
CustId Sum(Spend) ShopId
1 30 Could be 1 or could be 2
2 70 Could be 3 or could be 4
In your query this probably applies to the fields CTRL.ESITO, M.ID_CAT, M.QTA, M.DESCRIZ,
CTRL.ID_PUNTO, CTRL.ID_ADDETTO.
You are doing an implicit cross join on the tables. Try using different type of Join such as Inner, Right or Left.
example:
SELECT *
FROM CONTESTAZIONI c
INNER JOIN CONTROLLI ctrl ON c.ID = ctrl.ContId
One advantage of the modern (meaning post-1992) explicit JOIN notation is that you are less likely to forget joining conditions. You have 5 tables; you need (at least) 4 join conditions. Your SQL has only 2 join conditions (one of them a compound join). You've not given us enough schema to be sure of coming up with the right columns for joining, but your query should probably be something like:
SELECT C.ID_PASS, C.ID_MERCE, CTRL.ESITO, M.ID_CAT, M.QTA, M.DESCRIZ,
L.ID_PUNTO, L.ID_ADDETTO, C.DATE_OPEN, C.DATE_CLOSE, C.NOTE
FROM ADDETTI A
JOIN CONTROLLI L ON A.ID = L.ID_Addetto
JOIN CONTESTAZIONI C ON A.xxx1 = C.xxx2
JOIN FUNZIONARI F ON C.yyy1 = F.yyy2
JOIN MERCI M ON M.ID = C.ID_Merce AND M.ID_Pass = C.ID_Pass
WHERE A.ID_FUNZ=501
AND L.ESITO > 1;
Note that you showed the join of A and L (renamed from CTRL), and M and C. The joins of C to A and of F to C are semi-arbitrary guesses (and the column names xxx1 etc are placeholders for your real column names); you will need to understand your schema and make the appropriate joins.
Thanks to everbody. Now I understood: I have to join together all the tables that I put in select (of course only that are in relationship); without this join I get a cross product. I can do join either "JOIN...ON..." or "WHERE ...". I made join with WHERE. Now works ok:
SELECT C.ID_PASS, C.ID_PUNTO, C.ID_ADDETTO, C.TIME_START,
C.TIME_END, C.ESITO, P.ID_NAZ, C.ID_MERCE, M.QTA, M.DESCRIZ, M.ID_CAT
FROM CONTROLLI C, PASSEGGERI P, MERCI M, FUNZIONARI F, CATEGORIE, ADDETTI, NAZIONI
WHERE
ADDETTI.ID=C.ID_ADDETTO
AND P.ID=M.ID_PASS
AND P.ID_NAZ=NAZIONI.ID
AND M.ID_PASS=C.ID_PASS AND M.ID=C.ID_MERCE -- composite PK (so another AND reuqired)
AND M.ID_CAT=CATEGORIE.ID
AND F.ID=ADDETTI.ID_FUNZ
AND ESITO > 1
AND F.ID = 501
'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)
I got 2 tables: job and job_working_time
job: id (Increment, Index, Unique)
job_working_time: job_id(allow multiple), property_working_time
This SQL query returns the ids with multiple values or duplicates. It helps, but it doesn't fix my problem:
SELECT a.id AS id, count( b.job_id ) AS cnt, b.property_working_time AS value
FROM job a
INNER JOIN job_working_time b ON a.id = b.job_id
GROUP BY b.job_id
HAVING cnt >1
I want to remove duplicates, only for ids with duplicates, e.g: l = leave, r = remove
1 - 1 (l)
1 - 1 (r)
1 - 2 (l)
1 - 3 (l)
1 - 1 (r)
2 - 1 (l)
2 - 1 (r)
2 - 2 (l)
Thanks in advance
[Later edit]
One thing you should consider:
Anyway, when I want to delete the ID, will remove all values for it. So, the idea is to keep all the values for that id, so later I can add without duplicates. That's why it's so important to retrieve, both the id and the value, but not duplicate content. The SQL should return all the (l) values from the above e.g. list.
Since your example looks like you don't want any row be same
DISTINCT will work for you
it select completely diffirent rows
SELECT DISTINCT a.id AS id, count( b.job_id ) AS cnt, b.property_working_time AS value
FROM job a
INNER JOIN job_working_time b ON a.id = b.job_id
GROUP BY b.job_id
HAVING cnt >1
Edit:
Example added
https://data.stackexchange.com/stackoverflow/q/119267/
First/ simple Query:
SELECT id, field, count(*) c from ... group by field having c >1
Second Query, modifed for get IDs to delete:
SELECT instr(s,mid(s,',')+1) from (
SELECT group_concat(id) s, count(*) c from ... group by field having c >1)z
and the end:
Delete FROM ... WHERE id in ( ...)
looks ugly, but fast (Mid function performance is faster than not in (...)).