So there is a question I have not been able to find an answer to. Say you want to print each row in a table like the following:
ID | Name | Location
----+------+----------
1 | Adam | New York
2 | Eva | London
3 | Jon | New York
which would give the result
1 Adam New York
2 Eva London
3 Jon New York
Say that I at the same time would like to count the number of occurrences someone lives in a specific city, and save that value for printing after I've iterated through the table; is that possible? For example, printing the following:
1 Adam New York
2 Eva London
3 Jon New York
Inhabitants in New York: 2
Inhabitants in London: 1
Is this possible or would you have to iterate through the entire table twice by grouping by Location the second time, and counting those?
EDIT:
To clarify, I know I can solve it by calling:
SELECT * FROM table;
SELECT CONCAT('Inhabitants in ', Location, ': ', COUNT(ID))
FROM table
GROUP BY Location;
But now I am iterating through it twice. Is it possible to do it in only one iteration?
Generally speaking, yes, displaying every row from the table and displaying aggregated data is two separate tasks which should be handled by application, not by the database.
You have the option to run two queries - a plain select * from T, and select location, count(*) from T group by location, and displaying results sequentially. You also have the option to run only a select * from T one, and count the rows within your application, since you're displaying all rows anyway: use any dictionary-like structure your app language provides, with location string for key and running total integer for value.
If you're keen on keeping it a single query, check out WITH ROLLUP clause - https://dev.mysql.com/doc/refman/8.0/en/group-by-modifiers.html. This would certainly be an unusual way of using it, but if you group by location, id and then tamper with results a little, you can get what you want.
select if(id is null, CONCAT('Inhabitants in ', location, ': ', cnt), concat(id, ' ', name, ' ', location))
from
(
select id, location, name, count(*) cnt
from t
where location is not null
group by location, id with rollup
) q
where location is not null
order by id is null, id asc;
Though the performance could be questionable, compared to two plain queries; you should experiment or check with EXPLAIN.
Try below query, use subquery
select concat(concat(concat('Inhabitants in ',location),':'),total)
from
(select location, count(id) total
from tablename group by location)a
Related
To make it more clear, If I have this data in MySql:
name | allowance | age
----------------------
khan | 50 | 20
aal | 60 | 22
hyme | 50 | 21
khan | 61 | 20
notice that there are two 'khan' in the database with different allowance. I want to only show the name and the age but if I show it using the mysqli select statement, there would be two 'khan' but I only want to show only 1 'khan'. How can I do it?
You need to use GROUP_CONCAT to see agges of all Khans;
select name, GROUP_CONCAT(age) ages from Table group by name
or for minimum aged khan
select name , min(age) MiniumAge from Table group by name
or for elder khan
select name , max(age) MaxAge from Table group by name
or any khan
select name , age from Table group by name
.
Please try below query:-
SELECT name, age FROM table_name WHERE group by name
If you want any from multiple same record then simply used group by query.
I think you could do this:
SELECT name, age FROM table_name WHERE group by name,age
First thing: if both those "khan"s are the same person with two different allowances then your schema is not properly normalized and it will give you big troubles later - imagine you want to change "khan" to "Khan" - now you have to update it in multiple places instead once. Depending on your actual needs you may want one table of people (person_id, name, age), and table of allowances (person_id, allowance, [..some other parameters?..]).
Second, to really get what you want, either you use group by, to get one "random" row per each name as suggested in other answers, or you can do
SELECT DISTINCT name, age FROM table;
which will give you one row per each name-age combination, so khan-20 will be there only once - but if there were khan-25 then that is probably different person and you would have two khans returned, each with their own age.
You can try this mate:
SELECT DISTINCT
name, age
FROM
<your_table>;
or this one
SELECT
name, age
FROM
<your_table>
GROUP BY
name;
Q: Is there any chance that if there are 2 records of tha same name have difference value of age? If so, kindly update the question so that better answers will be given. Cheers!
Okay I'm still fairly new to MS Access, but have got some of the bases down. My next issue is pulling data from two different queries but still needing them to show.
Here's what I have
I have one query with the following information
| ID Number | Points |
The other query has the following
| ID Number | Points over 1000 |
In this new query I need to do display the following
| ID Number | Points | Points over 1000 | Total Points |
There's going to be some rows where Points over 1000 doesn't exist and needs to be empty or a 0, but I need the ID Number In Points over 1000 to match and check the ID Number in just the points column.
and in the end add them up in the Points total
I hope that makes sense?
Thanks again
In theory this Query should work the way you want it to.
SELECT
tmpQ.ID,
Sum(tmpQ.Points) As ActualPoints,
Sum(tmpQ.PointsOver1000) As Over1000,
[ActualPoints] + [Over1000] As TotalPoints
FROM
(
SELECT
qryA.[ID Number] As ID,
Sum(qryA.Points) As Points,
Sum(0) As PointsOver1000
FROM
qryA
GROUP BY
qryA.[ID Number]
UNION ALL
SELECT
qryB.[ID Number] As ID,
Sum(0) As Points,
Sum(qryB.PointsOver1000) As PointsOver1000
FROM
qryB
GROUP BY
qryB.[ID Number]
) As tmpQ
GROUP BY
tmpQ.ID;
Where qryA and qryB are the two queries you have that will give you the result of two different Points.
Below is the result set from SELECT query,
mysql> select * from mytable where userid =242 ;
+--------+-----------------------------+------------+---------------------+---------------------+
| UserId | ActiveLinks | ModifiedBy | DateCreated | DateModified |
+--------+-----------------------------+------------+---------------------+---------------------+
| 242 | 1|2|4|6|9|15|22|33|43|57|58 | 66 | 2013-11-28 16:17:25 | 2013-11-28 16:17:25 |
+--------+-----------------------------+------------+---------------------+---------------------+
What I want is to SELECT the records by splitting the Active links columns and associating it with UserId in the below format,
eg,
UserId ActiveLinks
242 1
242 2
242 4
242 6
Can anyone help me with this query , as of now nothing coming to my mind. Thanks
Dealing with lists stored in data is a pain. In MySQL, you can use substring_index(). The following should do what you want:
SELECT userid,
substring_index(substring_index(l.ActiveLinks, '||', n.n), '|', -1) as link
FROM (select 1 as n union all select 2 union all select 3 union all select 4) n join
ipadminuserslinks l
on length(l.ActiveLinks) - length(replace(l.ActiveLinks, '||', '')) + 1 <= n.n
WHERE userid = 242;
The first subquery generates a bunch of numbers, which you need. You may have to increase the size of this list.
The on clause limits the numbers to the number of elements in the list.
As you can probably tell, this is rather complicated. It is much easier to use a junction table, which is the relational way to store this type of information.
I would create a routine which will have the delimiter as an argument.
Another in_var would be the correspondent line.
Every time you call it, it will return the set of values for the UserId called.
It will basically use a loop based on the count of '|' (we call this pipeline)
This way you can implement the solution proposed by #Gordon Linoff without the need to know how many active links you have.
If this is just a list of values that do not relate to anything on another table I would do it the same way as Gordon (if needs be you can cross join the sub query that gets the lists of numbers to easily generate far larger ranges of numbers). One minor issue is that if the range of number is bigger than the number of delimited values on a row then the last value will be repeated (easily removed using DISTINCT in this case, more complicated when there are duplicate values in there that you want to keep).
However if the list of delimited values are related to another table (such as being the id field of another table then you could do it this way:-
SELECT a.UserId, b.link_id
FROM mytable a
LEFT OUTER JOIN my_link_table b
ON FIND_IN_SET(b.link_id, replace(a.ActiveLinks, '|', ','))
Ie, use FIND_IN_SET to join your table with the related table. In this case converting any | symbols used as delimiters to commas to allow FIND_IN_SET to work.
I have a table like this
id | user_id | code | type | time
-----------------------------------
2 2 fdsa r 1358300000
3 2 barf r 1358311000
4 2 yack r 1358311220
5 3 surf r 1358311000
6 3 yooo r 1358300000
7 4 poot r 1358311220
I want to get the concatenated 'code' column for user 2 and user 3 for each matching time.
I want to receive a result set like this:
code | time
-------------------------------
fdsayooo 1358300000
barfsurf 1358311000
Please note that there is no yackpoot code because the query was not looking for user 4.
You can use GROUP_CONCAT function. Try this:
SELECT GROUP_CONCAT(code SEPARATOR '') code, time
FROM tbl
WHERE user_id in (2, 3)
GROUP BY time
HAVING COUNT(time) = 2;
SQL FIDDLE DEMO
What you are looking for is GROUP_CONCAT, but you are missing a lot of details in your question to provide a good example. This should get you started:
SELECT GROUP_CONCAT(code), time
FROM myTable
WHERE user_id in (2, 3)
GROUP BY time;
Missing details are:
Is there an order required? Not sure how ordering would be done useing grouping, would need to test if critical
Need other fields? If so you will likely end up needing to do a sub-select or secondary query.
Do you only want results with multiple times?
Do you really want no separator between values in the results column (specify the delimiter with SEPARATOR '' in the GROUP_CONCAT
Notes:
You can add more fields to the GROUP BY if you want to do it by something else (like user_id and time).
Firstly I'd like to start by apologizing for the potentially miss-leading title... I am finding it difficult to describe what I am trying to do here.
With the current project I'm working on, we have setup a 'dynamic' database structure with MySQL that looks something like this.
item_details ( Describes the item_data )
fieldID | fieldValue | fieldCaption
1 | addr1 | Address Line 1
2 | country | Country
item_data
itemID | fieldID | fieldValue
12345 | 1 | Some Random Address
12345 | 2 | United Kingdom
So as you can see, if for example I wanted to lookup the address for the item 12345 I would simply do the statement.
SELECT fieldValue FROM item_data WHERE fieldID=1 and itemID=12345;
But here is where I am stuck... the database is relatively large with around ~80k rows and I am trying to create a set of search functions within PHP.
I would like to be able to perform a query on the result set of a query as quickly as possible...
For example, Search an address name within a certain country... ie: Search for the fieldValue of the results with the same itemID's as the results from the query:
'SELECT itemID from item_data WHERE fieldID=2 and fieldValue='United Kingdom'..
Sorry If I am unclear, I have been struggling with this for the past couple of days...
Cheers
You can do this in a couple of ways. One is to use multiple joins to the item_data table with the fieldID limited to whatever it is you want to get.
SELECT *
FROM
Item i
INNER JOIN item_data country
ON i.itemID = country.itemID
and fieldid = 2
INNER JOIN item_data address
ON i.itemID = country.itemID
and fieldid = 1
WHERE
country.fieldValue= 'United Kingdom'
and address.fieldValue= 'Whatever'
As an aside this structure is often referred to as an Entry Attribute Value or EAV database
Sorry in advance if this sounds patronizing, but (as you suggested) I'm not quite clear what you are asking for.
If you are looking for one query to do the whole thing, you could simply nest them. For your example, pretend there is a table named CACHED with the results of your UK query, and write the query you want against that, but replace CACHED with your UK query.
If the idea is that you have ALREADY done this UK query and want to (re-)use its results, you could save the results to a table in the DB (which may not be practical if there are a large number of queries executed), or save the list of IDs as text and paste that into the subsequent query (...WHERE ID in (...) ... ), which might be OK if your 'cached' query gives you a manageable fraction of the original table.