I've got tables like:
table A
id name email
1 test1 ex#ex.com
2 test2 ex#ex.com
3 test3 ex#ex.com
4 test4 ....
5 test5 ....
table B
id catA catB year member
1 false true 2011 2
2 true false 2011 3
3 fals true 2010 5
And i want to get every row in table A and sort it by following:
FIRST, get user 2 (current year, based on table B)
SECOND, get user 3 (current year, based on table B)
after that get users that is in table B
after that get all other users.
I know that i can have specific sql for getting the first two users, and the just the
rest. But shouldnt i be able to get them all with a nice ORDER by statement? Like limiting the first order statement to just affect the first row...
Something like this?
select A.id, A.name, A.email, B.catA, B.catB, B.year
from A
join B on A.id = B.member
ORDER BY B.year DESC, (B.member IS NOT NULL) DESC
First sort all results by the year field in table B, which gets you 2011, 2010, etc... Any members who are NOT listed in table B will have a null year and sort to the bottom of the list. Next sort by B.member not being null - mysql will coerce this boolean result into an integer 1 or 0, which can be sorted, So sort descending to make all the 1's (not null B.members) sort first.
Based on your sorting rules:
after that get users that is in table B
after that get all other users.
I assume that there are some users in table A that do not exist in B, so you'd want to use a LEFT JOIN.
SELECT a.id, a.name, a.email
FROM a
LEFT JOIN b
ON a.id = b.member
ORDER BY ISNULL(b.year), b.year DESC, a.name
You can always 'order by', however grotesquely complicated your select is, buy putting the data-gathering elements into a derived table, selecting from it, and ordering by the results. Something like...
SELECT col1,
col2,
col3
FROM
(SELECT 1 as col1,
col2,
' ' AS col3
FROM blah...blah...blah
UNION
SELECT 2 AS col1
col2,
col3
FROM blah...blah...blah
UNION
and so on) myderivedtable
ORDER BY col1,
col2,
col3
You just have to make sure all the columns you are selecting in each of the queries come out the same, or cope with a NULL value otherwise.
Related
I am having trouble with my sql query (Select distinct didnt work).
My sql is :
select distinct
count(T2.Column1)
from Table1 t2
where T2.Column1='2017-05-210'
The actual Column 1 data only have 3 data,
But the output is 12
Nb :
- Column1 data is having 1 to Many situation with Column2,
Here are the actual data:
Column 1 Column 2
1 A
1 B
1 C
1 D
2 A
2 B
2 C
2 D
3 A
3 B
3 C
3 D
Can anyone help me?
Really appreciate for your attention.
Thanks!
You want to count distinct values, so do count(distinct ):
select count(distinct T2.Column1)
from Table1 t2
where T2.Column1='2017-05-210'
(However, your sample data and the query's data/columns do not match.)
Your sample data, result and query do not match.
However, what your query does is:
Find all records with a column1 = '2017-05-210'.
Count all of these records where column1 is not null (which is true for all these records, as column1 = '2017-05-210').
This results in one number (one row, one column). But you additionally say with DISTINCT that you want to remove any duplicates from your result rows. With one row only there can be no duplicates, so the function is superfluous here.
So think about what you want to count really. You count distinct values (i.e. count ignoring duplicates) with COUNT(DISTINCT column), but COUNT(DISTINCT column1) would return 1 of course, because you are only looking for one value which is '2017-05-210' (or zero in case there is no record matching this value).
I have a mySQL dataset that looks like this:
ID PARENT_ID VALUE
1 100 This comment should be approved
2 100 Y
3 101 Another approved comment
4 101 Y
5 102 This comment is not approved
6 102 N
I need to construct an SQL query to select the rows that have a matching parent_id and corresponding value of Y (but ignore the rows with single letters as a value in the result) to result in:
ID PARENT_ID VALUE
1 100 This comment should be approved
3 101 Another approved comment
My idea is to use GROUP BY to combine the columns, but I can't work out how to select based on the Y/N values.
There is possibly a solution here How do I select a row based on a priority value in another row? but I don't think it is asking quite the same question.
Any ideas?
Although you can express this as an aggregation, you can express this using exists:
select d.*
from dataset d
where d.value <> 'Y' and
exists (select 1
from dataset d2
where d2.parent_id = d.parent_id and d2.value = 'Y'
);
This version is probably more efficient.
First, if you possibly can, change your table schema. Your table is storing two kinds of data in the same field (yes no flags and comments). This breaks normality and will haunt you later.
But if its not your table to change, you will need to self join. Try this.
SELECT a.id, a.parent_Id, a.value
FROM table a inner join table b
ON a.parent_id =b.parent_id
WHERE a.value <> 'Y' and b.value ='Y'
Given these entries in a table table:
user entry
A 1
A 2
A 5
A 6
B 1
B 2
B 3
B 4
B 5
B 6
C 1
C 4
D 1
D 2
D 5
D 6
D 7
D 9
And we have a subset entries_A to work with, which is the array [1,2,5,6].
Problems:
Find all users that have the same entries [1,2,5,6] and more, e.g. [1,2,5,6,7] or [1,2,3,5,6].
Find all users that have a lot of the same entries (and more), e.g. [1,2,5,9] or [2,5,6,3].
The best solution to the first problem I could come up with, is the following select query:
SELECT DISTINCT user AS u FROM table WHERE EXISTS (SELECT * FROM table WHERE entry=1 AND user=u)
AND EXISTS(SELECT * FROM table WHERE entry=2 AND user=u)
AND EXISTS(SELECT * FROM table WHERE entry=5 AND user=u)
AND EXISTS(SELECT * FROM table WHERE entry=6 AND user=u)
On the other hand, I get a feeling there's some algebraic vector-problem lurking below the surface (especially for problem two) but I can't seem to wrap my head around it.
All ideas welcome!
I think the easiest way to perform this type of query is using aggregation and having. Here is an example.
To get A's that have exactly those four elements:
select user
from table
group by user
having sum(entry in (1,2,5,6)) > 0 and
count(distinct entry) = 4;
To get A's that have those four elements and perhaps others:
select user
from table
group by user
having sum(entry in (1,2,5,6)) > 0 and
count(distinct entry) >= 4;
To order users by the number of matches they have and the number of other matches:
select count(distinct case when entry in (1, 2, 5, 6) then entry end) as Matches,
count(distinct case when entry not in (1, 2, 5, 6) then entry end) as Others,
user
from table
group by user
order by Matches desc, Others;
For the first problem:
SELECT user FROM (
SELECT
DISTINCT user
FROM
table
WHERE entry IN (1,2,5,6)
) a JOIN table b ON a.user = b.user
GROUP BY a.user
HAVING COUNT(*) >= 4
For the second problem just decrease the count in the having clause.
This is how I would to your first query (though I think Gordon Linoff's answer is more efficient):
select distinct user from so s1
where not exists (
select * from so s2 where s2.entry in (1,2,5,6)
and not exists (
select * from so s3 where s2.entry = s3.entry and s1.user = s3.user
)
);
For the second problem, you would need to specify what a lot should mean... three, four, ...
I have a MySQL table like this
id Name count
1 ABC 1
2 CDF 3
3 FGH 4
using simply select query I get the values as
1 ABC 1
2 CDF 3
3 FGH 4
How I can get the result like this
1 ABC 1
2 CDF 3
3 FGH 4
4 NULL 0
You can see Last row. When Records are finished an extra row in this format
last_id+1, Null ,0 should be added. You can see above. Even I have no such row in my original table. There may be N rows not fixed 3,4
The answer is very simple
select (select max(id) from mytable)+1 as id, NULL as Name, 0 as count union all select id,Name,count from mytable;
This looks a little messy but it should work.
SELECT a.id, b.name, coalesce(b.`count`) as `count`
FROM
(
SELECT 1 as ID
UNION
SELECT 2 as ID
UNION
SELECT 3 as ID
UNION
SELECT 4 as ID
) a LEFT JOIN table1 b
ON a.id = b.id
WHERE a.ID IN (1,2,3,4)
UPDATE 1
You could simply generate a table that have 1 column preferably with name (ID) that has records maybe up 10,000 or more. Then you could simply join it with your table that has the original record. For Example, assuming that you have a table named DummyRecord with 1 column and has 10,000 rows on it
SELECT a.id, b.name, coalesce(b.`count`) as `count`
FROM DummyRecord a LEFT JOIN table1 b
ON a.id = b.id
WHERE a.ID >= 1 AND
a.ID <= 4
that's it. Or if you want to have from 10 to 100, then you could use this condition
...
WHERE a.ID >= 10 AND
a.ID <= 100
To clarify this is how one can append an extra row to the result set
select * from table union select 123 as id,'abc' as name
results
id | name
------------
*** | ***
*** | ***
123 | abc
Simply use mysql ROLLUP.
SELECT * FROM your_table
GROUP BY Name WITH ROLLUP;
select
x.id,
t.name,
ifnull(t.count, 0) as count
from
(SELECT 1 AS id
-- Part of the query below, you will need to generate dynamically,
-- just as you would otherwise need to generate 'in (1,2,3,4)'
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
) x
LEFT JOIN YourTable t
ON t.id = x.id
If the id does not exist in the table you're selecting from, you'll need to LEFT JOIN against a list of every id you want returned - this way, it will return the null values for ones that don't exist and the true values for those that do.
I would suggest creating a numbers table that is a single-columned table filled with numbers:
CREATE TABLE `numbers` (
id int(11) unsigned NOT NULL
);
And then inserting a large amount of numbers, starting at 1 and going up to what you think the highest id you'll ever see plus a thousand or so. Maybe go from 1 to 1000000 to be on the safe side. Regardless, you just need to make sure it's more-than-high enough to cover any possible id you'll run into.
After that, your query can look like:
SELECT n.id, a.*
FROM
`numbers` n
LEFT JOIN table t
ON t.id = n.id
WHERE n.id IN (1,2,3,4);
This solution will allow for a dynamically growing list of ids without the need for a sub-query with a list of unions; though, the other solutions provided will equally work for a small known list too (and could also be dynamically generated).
I have two MySQL tables. What I am trying to do is to export the information where Value 1 is 1 less than Value 2 AND where ID_1 does not have its Value 1 and Value 2 equal.
Note:
Fields Value 1 and 2 are just integers.
Each distinct ID_A has the same Value_2
If there are two Value_1s that are one less than Value_2, look to Value_3 and select one that is higher
The reason why I have two tables here is because I am going to output information from both tables
We can write a script for this, but I need to do this in a single command for bonus points (which my instructor declared is possible)... I haven't even started a script for this, as I don't really know how to do that...
tableA looks like this:
ID_1 ID_2
A A
A B
B A
B B
C A
C B
C C
tableB looks like this:
ID_1 ID_2 Value_1 Value_2 Value_3
A A 2 3 NULL
A B 3 3 NULL
B A 4 5 NULL
B B 7 5 NULL
C A 7 8 98
C B 3 8 NULL
C C 7 8 56
The query should return this:
ID_1 ID_2
B A
C A
Here is what I have so far... And it keeps returning no hits, which is making me confused. I believe it is the AND clause after the first WHERE statement where I need to fix
SELECT CONCAT(...)
INTO OUTFILE '/tmp/outfile.tab'
FIELDS TERMINATED BY '\t'
ESCAPED BY ''
FROM tableA
INNER
JOIN tableB
ON tableA.ID_1 = tableB.ID_1
AND tableA.ID_2 = tableB.ID_2
WHERE tableB.Value_1 - 1 = tableB.Value_2
AND tableA.ID_1 !=
( SELECT DISTINCT
ID_1
FROM tableB
WHERE ID_1 = tableA.ID_1
AND Value_1 = Value_2
)
;
One final note: we issue all commands through putty, in which we can access MySQL
To be honest, I still don't understand exactly what you're trying to do, but I can explain why your query is returning no rows.
Look at this clause:
AND tableA.ID_1 !=
( SELECT DISTINCT
ID_1
FROM tableB
WHERE ID_1 = tableA.ID_1
AND Value_1 = Value_2
)
The subquery will necessarily always return either tableA.ID_1 or NULL. (Do you see why?) So the comparison is never "true"; it's always either "false" (because tableA.ID_1 != tableA.ID_1 is necessarily "false") or "null/indeterminate" (because tableA.ID_1 != NULL is "null/indeterminate"). Therefore, this clause filters out all results from your query — regardless of what the rest of your query might say.
I am not 100% sure of the question, but if I get it right, the first row of tableB (Line 25 in http://imgur.com/a/r3Qy5#1) should NOT be selected, because ID_1=A has Value_1=3 in the second row (Line 26 in http://imgur.com/a/r3Qy5#1), which is the same as Value_1 of the first row (Line 25 in http://imgur.com/a/r3Qy5#1).
So you could start with something like
SELECT .... FROM
tableA NATURAL JOIN tableB
WHERE Value_1=Value_2-1
AND Value_2 NOT IN (SELECT tb.Value_1 from tableB AS tb WHERE tb.ID_1=tableB.ID_1)
which fullfills requirements #1 and #2. For requirement #3 (if there are two rows for an ID_1, chose the one with the highest Value_3), we need to sort that on Value_3 and wrap it in a superquery for grouping:
SELECT .... FROM (
SELECT * FROM
tableA NATURAL JOIN tableB
WHERE Value_1=Value_2-1
AND Value_2 NOT IN (SELECT tb.Value_1 from tableB AS tb WHERE tb.ID_1=tableB.ID_1)
ORDER BY Value_3 DESC
) AS innerview
GROUP BY Value_1,Value_2
which gives the correct answer for the test data in your example.
You'll FIRST have to apply a test for your "Value_3" criteria grouped by the respective "ID_1" classification and Value1, value2. By applying the WHERE clause here, you are getting your final set of records INCLUSIVE of what WOULD be the highest value 3 entry in its result set. Now, that gets joined again to tableB AGAIN, but matching the qualifying entries. Since the COALESCE() will change any NULL value to 0 in the first result set, the JOIN clause must also match that. As in the case for the "A" and "B" groups where no Value_3 was applied, yet in the "C" group, it WILL have a valid value and pre-result in the entry with the max value of 98. That said, when re-joined back to instance "tb2" for TableB a second time will get the proper ID_2 of "A" for that set.
select
MaxQualified.ID_1,
tb2.ID_2,
MaxQualified.Value_1,
MaxQualified.Value_2,
tb2.Value_3
from
( select
tb.ID_1,
tb.Value_1,
tb.Value_2,
MAX( COALESCE( tb.Value_3, 0 ) ) as HighestVal3
from
TableB tb
where
tb.Value_1 +1 = tb.Value_2
group by
tb.ID_1,
tb.Value_1,
tb.Value_2 ) MaxQualified
JOIN TableB tb2
on MaxQualified.ID_1 = tb2.ID_1
AND MaxQualified.Value_1 = tb2.Value_1
AND MaxQualified.Value_2 = tb2.Value_2
AND MaxQualified.HighestVal3 = COALESCE( tb2.Value_3, 0 )
Now, that being said, and this is homework, this COULD fail or give multiple answers if you had multiple ID1, Value1, Value2, Value3 entries. It would return all "ID2" instances of the exact same common criteria. You would have to do even one more level nested to remove that level of distinction.
Your answer should ALSO return "A", "A", 2, 3