Concatenating multiple rows into single line in MS Access [duplicate] - ms-access

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Combine rows in Access 2007
Access 2007 - Concatenate fields from one column in one table into a single, comma delmited value in another table
Currently I have a table structure that is somewhat like this:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP
Bob -------C1-------Inf--------7Per--------0.05------0-----ADC2
Bob -------C1-------Inf--------7Per--------0.05------2-----BAC2
Bob -------C1-------Inf--------7Per--------0.05------0-----RBE2
Bob -------C1-------Inf--------7Per--------0.05------8-----VBE2
Bob -------C1-------Inf--------7Per--------0.05------6-----AEC2
Bob -------C1-------Inf--------7Per--------0.05------0-----PBC2
Bob -------C2-------Com------8Per--------0.45------1-----XBC4
Bob -------C2-------Com------8Per--------0.45------0-----AEC2
Bob -------C2-------Com------8Per--------0.45------0-----PBC2
Bob -------C2-------Com------8Per--------0.45------3-----ADC2
Bob -------C2-------Com------8Per--------0.45------0-----ADC2
Bob -------C2-------Com------8Per--------0.45------0-----BAC2
Joe--------C1-------Inf---------7Per--------0.05------0-----PBC2
Joe--------C1-------Inf---------7Per--------0.05------0-----ZTM2
Joe--------C1-------Inf---------7Per--------0.05------2-----QYC2
Joe--------C1-------Inf---------7Per--------0.05------0-----FLC2
Joe--------C1-------Inf---------7Per--------0.05------1-----KSC2
Joe--------C1-------Inf---------7Per--------0.05------0-----JYC2
What i'm looking to do is have 1 line per "Name" and per "Cat", that will sum up all the "Err" (per "Name" and "Cat") and concatenate only the "BP" fields into a single line. Such as:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP
Bob -------C1-------Inf--------7Per--------0.05-----16-----BAC2, VBE2, AEC2
Bob -------C2------Com------8Per--------0.45------4------XBC4, ADC2
Joe--------C1-------Inf--------7Per--------0.05------3------QYC2, KSC2
There have been similar questions asked but I cannot seem to apply it as my knowledge of VBA scripting is beginner. Is there any way to do all of this via SQL? If VBA scripting is the only option (ie. creating a function), any help would be greatly appreciated. Thank You in advance.
Question part 2:
I created the function as per Allen Browne's guide. The module is saved as modConcatRelated. Now, i've tried to run this query (im not sure if this is the correct SQL to get the result that i'm looking for):
SELECT
[Name],
[Cat],
[Desc],
[Thresh],
[Perc],
sum([Err]),
ConcatRelated("[BP]", "make_table_bp", "[Err] = " & [BP])
FROM make_table_bp
GROUP BY
[Name],
[Cat],
[Desc],
[Thresh],
[Perc],
[Err],
[BP];
It said "Error 3061. Too few parameters. Expected 1." Also it said "Undefined Function ConcatRelated." I'm looking for guidance on how to create the correct SQL statement so that I can call the ConcatRelated function correctly and yield the result as depicted above. Thanks again.
Next question:
What if the table had a unique date field tagged on as the last column in the table. Something like this:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP --- Date
Bob -------C1-------Inf--------7Per--------0.05------0-----ADC2--12/02/2011
Bob -------C1-------Inf--------7Per--------0.05------2-----BAC2--09/05/2011
Bob -------C1-------Inf--------7Per--------0.05------0-----RBE2--11/02/2011
Bob -------C1-------Inf--------7Per--------0.05------8-----VBE2--08/14/2012
Bob -------C1-------Inf--------7Per--------0.05------6-----AEC2--02/25/2009
Bob -------C1-------Inf--------7Per--------0.05------0-----PBC2--07/02/2011
Bob -------C2-------Com------8Per--------0.45------1-----XBC4--09/05/2011
Bob -------C2-------Com------8Per--------0.45------0-----AEC2--02/02/2010
Bob -------C2-------Com------8Per--------0.45------0-----PBC2--08/14/2012
Bob -------C2-------Com------8Per--------0.45------3-----ADC2--05/05/2001
Bob -------C2-------Com------8Per--------0.45------0-----ADC2--08/02/2010
Bob -------C2-------Com------8Per--------0.45------0-----BAC2--06/17/2010
Joe--------C1-------Inf---------7Per--------0.05------0-----PBC2--08/14/2012
Joe--------C1-------Inf---------7Per--------0.05------0-----ZTM2--09/05/2011
Joe--------C1-------Inf---------7Per--------0.05------2-----QYC2--05/17/2010
Joe--------C1-------Inf---------7Per--------0.05------0-----FLC2--3/19/2010
Joe--------C1-------Inf---------7Per--------0.05------1-----KSC2--09/05/2011
Joe--------C1-------Inf---------7Per--------0.05------0-----JYC2--08/14/2012
Let's say I wanted to build a query to say something like: show me all records still within this same format:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP
Bob -------C1-------Inf--------7Per--------0.05-----16-----BAC2, VBE2, AEC2
Bob -------C2------Com------8Per--------0.45------4------XBC4, ADC2
Joe--------C1-------Inf--------7Per--------0.05------3------QYC2, KSC2
But for a date range of 01/01/2009 to 09/31/2011
#HansUp could you help with this?

I used a subquery for the GROUP BY which computes the Sum of Err for each group. Then I added the ConcatRelated function (from Allen Browne) with the fields returned by the subquery. This is the query and the output (based on your sample data in make_table_bp) from the query:
SELECT
sub.[Name],
sub.Cat,
sub.[Desc],
sub.Thresh,
sub.Perc,
sub.SumOfErr,
ConcatRelated("BP",
"make_table_bp",
"[Err] > 0 AND [Name] = '" & sub.[Name]
& "' AND Cat = '"
& sub.Cat & "'",
"BP")
AS concat_BP
FROM
(SELECT
q.[Name],
q.Cat,
q.[Desc],
q.Thresh,
q.Perc,
Sum(q.[Err]) AS SumOfErr
FROM make_table_bp AS q
GROUP BY
q.[Name],
q.Cat,
q.[Desc],
q.Thresh,
q.Perc
) AS sub
ORDER BY
sub.Name,
sub.Cat;
The query outputs this result set:
Name Cat Desc Thresh Perc SumOfErr concat_BP
Bob C1 Inf 7Per 0.05 16 AEC2, BAC2, VBE2
Bob C2 Com 8Per 0.45 4 ADC2, XBC4
Joe C1 Inf 7Per 0.05 3 KSC2, QYC2
Notice I enclosed Name, Desc, and Err with square brackets every place they were referenced in the query. All are reserved words (see Problem names and reserved words in Access). Choose different names for those fields if possible. If not, use the square brackets to avoid confusing the db engine.
But this will not work unless/until your copy of the ConcatRelated function is recognized by your data base engine. I don't understand why it's not; I followed the same steps you listed for storing the function code, and this works fine on my system.
Edit: I tested that query with my version of the table, which has [Err] as a numeric data type. Sounds like yours is text instead. In that case, I'll suggest you change yours to numeric, too. I don't see the benefit of storing numerical values as text instead of actual numbers.
However if you're stuck with [Err] as text, you can adapt the query to deal with it. Change this ...
"[Err] > 0 AND [Name] = '" & sub.[Name]
to this ...
"Val([Err]) > 0 AND [Name] = '" & sub.[Name]
That change prevented the "Data type mismatch in criteria expression" error when I tested with [Err] as text data type. However, I also changed this ...
Sum(q.[Err]) AS SumOfErr
to this ...
Sum(Val(q.[Err])) AS SumOfErr
AFAICT that second change is not strictly necessary. The db engine seems willing to accept numbers as text when you ask it to Sum() them. However I prefer to explicitly transform them to numerical values rather than depend on the db engine to make the right guess on my behalf. The db engine has enough other stuff to deal with, so I try to tell it exactly what I want.
Edit2: If you want only unique values concatenated, you can modify the ConcatRelated() function. Find this section of the code ...
'Build SQL string, and get the records.
strSql = "SELECT " & strField & " FROM " & strTable
and change it to this ...
'Build SQL string, and get the records.
strSql = "SELECT DISTINCT " & strField & " FROM " & strTable

Related

How to split string then compare it to fill id's in relation?

I have 2 Tables:
Molecule containing :
-id
-MainName (ex: caffeine)
JsonTextMining containing :
-id
-solrId (ex: PMC54233)
-MoleculeName (ex: caffeine | aspirin | sugar )
They are ManyToMany relation so there is a third table jsonTextMiningMolecule that have:
-json_text_mining_id
-molecule_id
I want to find a postgresql command that can split the moleculeName string and then compare with mainName to attribute id's in jsonTextMiningMolecule
For the moment i got something like this :
edit:
update json_text_mining_molecule SET molecule_id = molecule.id
FROM molecule, json_text_mining
WHERE split_part(json_text_mining.molecule_name, ' | ', 2 ) = molecule.main_name
The result of this command is update 0 (perhap's because i have non null constraint on json_text_mining_id) and split_part don't work as he need to choose one part of the string
Try looking into split_part command.
https://www.postgresql.org/docs/9.1/static/functions-string.html
You can find many other string operations in there!
EDIT:
Try regexp_split_to_array with IN clause

Add Column in Table with conditional in block WHERE

I was doing a query with MySQL to save all objects returned, but I'd like identify these objects based in statements of the block WHERE, that is, if determined object to satisfy the specific characteristic I'd like create one column and in this column I assignment the value 0 or 1 in the row corresponding the object if it satisfy or not satisfy these characteristic.
This is my script:
SELECT
s.id, al.ID, al.j, al.k, al.r, gal.i
FROM
datas as al
WHERE
AND s.id = al.ID
AND al.j between 1 and 1
AND al.k BETWEEN 15 and 16
AND al.r BETWEEN 67 and 72
The script above is working perfectly and I can to save all objects which it return.
So, I'd like to know if is there a way add in the query above, on block WHERE, the following statement,
( Flags & (dbo.environment('cool') +
dbo.environment('ok') -
dbo.environment('source')) ) = 25
and ((al_pp x al_pp1)-0.5/3=11
and determined the objects that satisfy or not these condition with 0 or 1 in a new column created in Table saved.
I read some tutorials about this and saw some attempts with IF, CASE, ADD COLUMN or WHEN, but none of these solved.
Thanks in advance
MySQL has if function, see here
So you can simply use it in your query:
SELECT IF(( Flags & (dbo.fPhotoFlags('SATURATED') +
dbo.fPhotoFlags('BRIGHT') +
dbo.fPhotoFlags('EDGE')) ) = 0
and petroRad_r < 18
and ((colc_u - colc_g) - (psfMag_u - psfMag_g)) < -0.4
, 1 --// VALUE IF TRUE
, 0 --// VALUE IF FALSE
) as conditional_column, ... rest of your query

update single varchar field in table from several of same type in other database and table and combine with line breaks

If my answer is in another post, I've not found it. A post I thought might have my answer was
"I want to concatenate 2 strings from 2 textareas and insert them into a column in my table."
I am converting some data. Other database has text that is stored in the same table, different fields. each field (x.description_plain_text has a sequence number as illustrated in the script. As you can maybe see with my attempt, I would like to bring both of the text lines into one (varchar(8000)) field and separate with a line or two. I don't know if I am allowed to tag a second objective, but if/after I get these separate lines from the other database into one field in my new database I then want to be able to put an identifier next to each ... as I am trying to show in the 2nd illustration ...
1st illustration
--select x.description_plain_text, x.SEQ_NO
update MIC.dbo.Item set CustomerDocumentNote =
case
when x.SEQ_NO = 1 then cast(x.description_plain_text as varchar(8000))
when x.SEQ_NO = 2 then cast(x.description_plain_text as varchar(8000))
END
-- x.description_plain_text + CHAR(13) + CHAR(10) + cast(x.description_plain_text as varchar (8000))
from MIC.dbo.Item a
inner join in_item_xdesc x on x.item_id = a.itemid
where (a.ItemNumber = '14661')--(IS_PRINT_ACKNOW = 'Y' and SEQ_NO = 2)
2nd illustration ... need a SQL query that will give me just the description with P_A ... P_A is merely an identifier ... can be anything ... just a way to say If P_A then print but IF
P_PT_PO THEN print ...
P_A - Heater with 1.5" OD flange at 2.5", 48" mica leads with 36" SS braid exiting 90° from sheath, single clip support. 800 Watts & 240 Volts. For Gala pellitizer.
+ CHAR(13) +
P_PT_PO - Stamp "MIC #14661" on OD of heater. Silicone over Cement at lead ends.

Access query where one field is LIKE another

I'm trying to query on on field in one table where it is LIKE a field in another table but am having trouble getting valid results.
I want to find the Pager_ID in tbl_Emergin_Current_Device_Listing_20121126 where it is like the Pager_ID in tbl_AMCOM_PROD.
Some relevant information:
Pager_ID in tbl_Emergin_Current_Device_Listing_20121126 is at most 10 characters and are always numeric characters (example of 10 character Pager_ID: 3145551212).
However, Pager_ID in tbl_AMCOM_PROD can be alpha-numeric (3145551212#att.txt.com, which would be the same user.
All data is stored as text.
I want to be able to find "3145551212#att.txt.com" in tbl_Amcom_Prod.Pager_ID when "3145551212" is present in tbl_Emergin_Current_Device_Listing_20121126.Pager_ID. However, with the code below I'm only finding exact matches (EQUAL instead of LIKE).
current code:
SELECT DISTINCT tbl_emergin_current_device_listing_20121126.userrecno,
tbl_emergin_current_device_listing_20121126.username,
tbl_emergin_current_device_listing_20121126.department,
tbl_emergin_current_device_listing_20121126.carriername,
tbl_emergin_current_device_listing_20121126.protocol,
tbl_emergin_current_device_listing_20121126.pin,
tbl_emergin_current_device_listing_20121126.pager_id,
Iif([tbl_amcom_group_call_leads_and_id].[amcom listing msg id],
[tbl_amcom_group_call_leads_and_id].[amcom msg group id],
[tbl_amcom_prod].[messaging_id])
AS [Amcom Messaging or Message Group ID]
FROM ((tbl_emergin_current_device_listing_20121126
LEFT JOIN tbl_amcom_prod
ON tbl_emergin_current_device_listing_20121126.pager_id =
tbl_amcom_prod.pager_id)
LEFT JOIN tbl_amcom_group_call_leads_and_id
ON tbl_emergin_current_device_listing_20121126.pager_id =
tbl_amcom_group_call_leads_and_id.[ams group call lead])
LEFT JOIN tbl_deactivated_pager_list
ON tbl_emergin_current_device_listing_20121126.pager_id =
tbl_deactivated_pager_list.[pager number];
Sample Results:
UserRecNo UserName Department CarrierName Protocol PIN PAGER_ID Amcom Messaging or Message Group ID
43 Brown, Lewis BJH Verizon 0 3145550785 3145550785 3145550785
52 Wyman, Mel BJH Airtouch (Verizon) (SNPP) 3 3145558597 3145558597 3145558330
I'd also like to see this record but am not with current code:
57 Johnson, Mick BJH AT&T 3 3145551234 3145551234#att.txt.com 3145559876
What change should I be making?
Thanks in advance!
Something like:
SELECT Pager_ID
FROM tbl_Amcom_Prod a
LEFT JOIN [tbl_Emergin_Current_Device_Listing_20121126] b
On a.Pager_ID & "*" Like b.Pager_ID
This will only work in SQL view, not design view.
You could also use a mixture of Instr & Mid.
SELECT IIf(InStr([Pager_ID] & "",".")>0,
Mid([Pager_ID],1,InStr([Pager_ID],".")-1),[Pager_ID ]) AS PID
FROM [tbl_Amcom_Prod]
WHERE IIf(InStr([Pager_ID] & "",".")>0,
Mid([Pager_ID],1,InStr([Pager_ID],".")-1),[Pager_ID])
In (SELECT Pager_ID
FROM [tbl_Emergin_Current_Device_Listing_20121126])

Merge like dates in MS Access

I am a pilot who flies multiple legs in a day. The software I use to log flights spits out a csv file and lists every leg separately. I import the csv file into table 1 in ms access. I would like to merge all flights from the same day into one record on a new table. My problem is combining the route and adding the time.
Table 1
Date Plane From To Time
2009-10-13 111WS CHO LGA 120
2009-10-13 111WS LGA ITH 100
2009-10-13 111WS ITH LGA 90
2009-10-13 111WS LGA BOS 110
Table 2
Date Plane Route Time
2009-10-13 111WS CHO-LGA-ITH-LGA-BOS 420
I would like to use VBA code to do this, but I haven't done any programming in 12 years and unfortunately don't have the time to relearn. I don't think the code has to be too elaborate, it seems pretty straightforward. I just don't know how to do it. I hope someone can help me out. Thanks in advance.
Note:
I am using MS Access 97 (hope that's not a problem)/
The date field is a string, not a date/
The time is in minutes, and can stay that way/
There normally will not be more than 80 records in table 1/
There can be anywhere from one to eight flights in one day/
Create a Totals query, bring in your table, and include the Date and Time as columns. The Date Column should be set to Group By in the Total Row, and the Time should be set to Sum. You will also need another column to get the final entry in the route, so put the To column in the grid also, and set the Totals row for that column to Last.
To get the remainder of the route, you will need to use a combining function like this one:
Return a concatenated list of sub-record values
http://www.mvps.org/access/modules/mdl0004.htm
This will combine the FROM column into a single value, which you can include as another column in the output. Set the Total row for this column to Expression.
To get the complete route, combine the concatenated FROM columm with the LAST TO column.
Note that you don't need to build the entire query at once. Build each of the three pieces (total time, concatenated route, ending destination) individually (in its own query), and make sure each piece works individually, before combining them into a single query.
Add module
Public Function ConcatField(FieldName As String, TableName As String, Where As String, Optional Delimeter = "-", Optional OrderBy = "") As String
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT " & FieldName & " FROM " & TableName & " WHERE " & Where & IIf(OrderBy > "", " ORDER BY " & OrderBy, ""))
ConcatField = DLookup("From", "RTE", Where)
While Not rs.EOF
ConcatField = ConcatField + IIf(ConcatField = "", "", Delimeter) + rs.Fields(0)
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
End Function
and run query
Worked on mine
SELECT rte.Date, rte.Plane, ConcatField("to","rte","Date='" & [Date] & "' AND Plane='" & [Plane] & "'") AS Expr1, Sum(rte.Time) AS SumOfTime
FROM rte
GROUP BY rte.Date, rte.Plane, ConcatField("to","rte","Date='" & [Date] & "' AND Plane='" & [Plane] & "'");
enter code here
Unlike ACE (Access 2007), the Jet 3.51 engine (Access97) doesn't have multivalue types. SQL the language (including the Access Database Engine's own proprietary SQL) does not have a 'Concatenate' function because it would be a violation of first normal form (1NF) which requires scalar types. So this isn't something for a SQL query. Sounds to me more like a candidate for a report.
Speaking of 1NF, considering it is possible to fly to the same destination twice in one day, your table lacks a relational key. It sounds like you need to replace you single 'date' column that is typed as 'text' with a pair of DATETIME values representing a period, with the required 'sequenced primary key' e.g. a CHECK constraint to prevent overlapping periods. Temporal databases are definitely non-trivial!
Thanks for all your responses. I used "THEn's" answer, but I had to change a few things (hope that's not a problem). I only needed the flights grouped by date, so I took out the grouping by plane, and just logged the first plane on the first leg of that day. Also I just found out that my software exports the csv file in reverse order, so I changed the module a little to account for this. So this is what the imported data looks like (I start and end in CHO):
Date Plane From To Time
2009-10-14 111WS LGA CHO 120
2009-10-14 111WS BOS LGA 110
2009-10-13 111WS LGA BOS 110
2009-10-13 111WS ITH LGA 90
2009-10-13 111WS LGA ITH 100
2009-10-13 111WS CHO LGA 120
This is the Module:
Public Function ConcatField(FieldName As String, TableName As String, Where As String, Optional Delimeter = "-") As String
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT " & FieldName & " FROM " & TableName & " WHERE " & Where)
rs.MoveLast
While Not rs.BOF
ConcatField = ConcatField + IIf(ConcatField = "", "", Delimeter) + rs.Fields(0)
rs.MovePrevious
Wend
ConcatField = ConcatField + "-" + DLookup("To", "rte", Where)
rs.Close
Set rs = Nothing
End Function
This is the query:
SELECT rte.Date, First(rte,plane), ConcatField("From","rte","Date='" & [Date] & "'") AS Expr1, Sum(rte.time) AS [Total Time]
FROM rte
GROUP BY rte.Date;
This causes a problem because I'm using a field called "From" in the openrecordset line, I tried renaming the field to something else and it worked perfectly. However I was hoping to keep the field names the way they are. It worked when I was using the field name "To" in the openrecordset line, but then I was running into a problem with the data being in reverse order. So I was looking for any suggestions, but I would like to keep the field names the same, and I would like to keep the table in reverse order if possible. Thanks again guys.