I know that in SQL I can use the 'String_agg(Test1, ',')' function for grouping rows and concatenate values in a selected field ('Test1' in this case).
For Example:
I have a query that the result without using String_agg on 'Buyer' field is:
**Key** | **Buyer** | **MP**
1 | Josh | Gregory
1 | Bred | Gregory
2 | John | Ethan
The expected results when using String_agg is:
**Key** | **Buyer** | **MP**
1 | Josh, Bred | Gregory
2 | John | Ethan
But the problem is that I'm trying to execute it in SQL query which retrieves data to Excel file from another Excel file and it fails because of an error that seems like the Excel query doesn't know the String_agg function.
The query is:
SELECT `Sheet1$`.Key, string_agg(`Sheet1$`.Buyer, `, `) AS `Buyer`, `Sheet1$`.MP
FROM `C:\Input\Data.xls`.`Sheet1$` `Sheet1$`
GROUP BY 2
ORDER BY `Sheet1$`.Key
Screenshot:
Query screenshot
Error:
Error Screenshot
Someone can help me and tell me how should I correct my query to make it works?
Thank you!
Problem: Excel is not a database.
You are trying to used advanced query functionality in a spreadsheeting package, which is sometimes somewhat supported in some versions of excel, uses lots of processor power, causes serious issues as soon as a user moves anything on the sheet, or the file itself, and is not really what it was designed to do.
Solution: Use a database.
Have a bit of a look at the excel 'concatenate' function.
I believe you can use it as CONCAT() also.
Also see this SO question: Concatenation in SQL select query on Excel sheet
Hope this helps.
Related
I have a quick question regarding writing a SQL query to obtain a complete entry from two or more entries where the data is missing in different columns.
This is the example, suppose I have this table:
Client Id | Name | Email
1234 | John | (null)
1244 | (null) | john#example.com
Would it be possible to write a query that would return the following?
Client Id | Name | Email
1234 | John | john#example.com
I am finding this particularly hard because these are 2 entires in the same table.
I apologize if this is trivial, I am still studying SQL and learning, but I wasn't able to come up with a solution for this and I although I've tried looking online I couldn't phrase the question in the proper way, I suppose and I couldn't really find the answer I was after.
Many thanks in advance for the help!
Yes, but actually no.
It is possible to write a query that works with your example data.
But just under the assumption that the first part of the mail is always equal to the name.
SELECT clients.id,clients.name,bclients.email FROM clients
JOIN clients bclients ON upper(clients.name) = upper(substring(bclients.email from 0 for position('#' in bclients.email)));
db<>fiddle
Explanation:
We join the table onto itself, to get the information into one row.
For this we first search for the position of the '#' in the email, get the substring from the start (0) of the string for the amount of characters until we hit the # (result of positon).
To avoid case-problems the name and substring are cast to uppercase for comparsion.
(lowercase would work the same)
The design is flawed
How can a client have multiple ids and different kind of information about the same user at the same time?
I think you want to split the table between clients and users, so that a user can have multiple clients.
I recommend that you read information about database normalization as this provides you with necessary knowledge for successfull database design.
I have a data set like the following:
+-----------------+---------------------+
| job_code | job_title |
+-----------------+---------------------+
| finance_acct | Business Accountant |
| finance_manager | Business Manager |
| it_programmer | IT Programmer |
| it_manager | IT Manager |
+-----------------+---------------------+
etc.
I want to take all of the job titles that share the same first half of their job code and print them as a list. Like the following:
finance: Business Accountant, Business Manager
it: IT Programmer, IT Manager
How would I do so? I know how to use SUBSTR to pull the first part of the job code. Basically I can create the left column fine. I ran into a couple of problems though:
Using the GROUP BY command, I continually got ORA-00979 error ("not
a GROUP BY expression").
I can't figure out how to make the list delimited with commas. I
used CONCAT but even then you end up with a superfluous comma after
the last entry for a given line. I've seen some things online about
the STUFF command, but I know it's possible to do so without this.
Any tips? Thank you.
regexp_substr() comes to mind to extract the part you want from the job_code. The rest is just aggregation and listagg():
select regexp_substr(job_code, '[^_]+', 1, 1) as half_job_code,
listagg(job_title, ', ') within group (order by job_title) as job_titles
from t
group by regexp_substr(job_code, '[^_]+', 1, 1)
Try the listagg function. you can specify a delimited and group it based on the data you require.
A query I am working on is showing a rather interesting behaviour that I couldn't debug so far.
This is the query before it gets buggy:
QryCount
SELECT EmpId, [Open/Close], Count([Open/Close]) AS Occurences, Attribute1, Market, Tier, Attribute2, MtSWeek
FROM qrySource
WHERE (Venue="NewYork") AND (Type="TypeA")
GROUP BY EmpId, [Open/Close], Attribute1, Market, Tier, Attribute2, MtSWeek;
The query gives precisely the results that I would expect it to:
#01542 | Open | 5 | Call | English | Tier1 | Complain | 01/01/2017
#01542 | Closed | 2 | Call | English | Tier2 | ProdInfo | 01/01/2017
#01542 | Open | 7 | Mail | English | Tier1 | ProdInfo | 08/01/2017
etc...
But as a matter of fact in doing so it provides more records than needed at a subsequent step thereby creating cartesians.
qrySource.[Open/Close] is a string type field with possible attributes (you guessed) "open", "Closed" and null and it is actually provided by a mapping table at the creation stage of qrySource (not sure, but maybe this helps).
Now, the error comes in when I try to limit qryCount only to records where Open/Close = "Open".
I tried both using WHERE and HAVING to no avail. The query would result in 0 records, which is not what I would like to see.
I thought that maybe it is because "open" is a reserved term, but even by changing it to "D_open" in the source table didn't fix the issue.
Also tried to filter for the desired records in a subsequent query
SELECT *
FROM QryCount
WHERE [Open/Close] ="D_Open"
But nothing, still 0 records found.
I am suspicious it might be somehow related to some inherent proprieties of the COUNT function but not sure. Any help would be appreciated.
Everyone who participated, thank you and apologies for providing you with insufficient/confusing information. I recon the question could have been drafted better.
Anyhow, I found that the problem was apparently caused by the "/" in the Open/Closed field name. As soon as I removed it from the field name in the original mapping table the query performed as expected.
First: I'm using Access 2010.
What I need to do is pull everything in a field out that is NOT a certain string. Say for example you have this:
00123457*A8V*
Those last 3 characters that are bolded are just an example; that portion can be any combination of numbers/letters and from 2-4 characters long. The 00123457 portion will always be the same. So what I would need to have returned by my query in the example above is the "A8V".
I have a vague idea of how to do this, which involved using the Right function, with (field length - the last position in that string). So what I had was
SELECT Right(Facility.ID, (Len([ID) - InstrRev([ID], "00123457")))
FROM Facility;
Logically in this mind it would work, however Access 2010 complains that I am using the Right function incorrectly. Can someone here help me figure this out?
Many thanks!
Why not use a replace function?
REPLACE(Facility.ID, "00123457", "")
You are missing a closing square bracket in here Len([ID)
You also need to reverse this "00123457" in InStrRev(), but you don't need InStrRev(), just InStr().
If I understand correctly, you want the last three characters of the string.
The simple syntax: Right([string],3) will yield the results you desire.
(http://msdn.microsoft.com/en-us/library/ms177532.aspx)
For example:
(TABLE1)
| ID | STRING |
------------------------
| 1 | 001234567A8V |
| 2 | 008765432A8V |
| 3 | 005671234A8V |
So then you'd run this query:
SELECT Right([Table1.STRING],3) AS Result from Table1;
And the Query returns:
(QUERY)
| RESULT |
---------------
| A8V |
| A8V |
| A8V |
EDIT:
After seeing the need for the end string to be 2-4 characters while the original, left portion of the string is 00123457 (8 characters), try this:
SELECT Right([Table1].[string],(Len([Table1].[string])-'8')) AS Result
FROM table1;
Suppose I have a SQL query like this:
SELECT
tickets.TicketNumber, history.remarks
FROM
AT_DeviceReplacement_Tickets tickets
INNER JOIN
AT_DeviceReplacement_Tickets_History history
ON tickets.TicketNumber = history.TicketNumber;
I get a table like this in repsonse:
ticketNumber | remarks
-------------+------------
1 | "Hello, there is a problem."
1 | "Did you check the power cable?
1 | "We plugged it in and now it works. Thank you!"
2 | "Hello, this is a new ticket."
Suppose that I want to write a query that will concatenate the remarks for each ticket and return a table like this:
ticketNumber | remarks
-------------+------------
1 | "Hello, there is a problem.Did you check the power cable?We plugged it in and now it works. Thank you!"
2 | "Hello, this is a new ticket."
Yes, in the real code, I've actually got these sorted by date, among other things, but just for the sake of discussion, how would I edit the above query to get the result I described?
Have a look at the following questions:
Can I Comma Delimit Multiple Rows Into One Column?
Is it possible to concatenate column values into a string using CTE?
The cleanest solution to this problem is DB dependent. Lentine's links show very ugly solutions for Oracle and SQL Server and a clean one for MySQL. The answer in PostgreSQL is also very short and easy.
SELECT ticket_number, string_agg(remarks, ', ')
FROM
AT_DeviceReplacement_Tickets tickets
INNER JOIN
AT_DeviceReplacement_Tickets_History history
ON tickets.Ticket_Number = history.Ticket_Number
GROUP BY tickets.ticket_number;
(Note you have both ticket_number and TicketNumber in your sample code.)
My guess is that Oracle and SQL Server either (1) have a similar aggregate function or (2) have the capability of defining your own aggregate functions. [For MySQL the equivalent aggregate is called GROUP_CONCAT.] What DB are you using?