Multiple taxonomy term repeating results in views. Remove repetition but keep the term - mysql

NOTE: I dont want to remove the repeating node, more like merging them.
I have a view that pulls a seminar content type along with the taxonomy term attached to the content type. In the content type the term reference field pulling the taxonomy term is a multivalue field. So whenever there is more than one taxonomy term attached to the node the view result is repeated. So using view and its api what I want is
What I have now when view pulls the result is
Nid Speaker name | Location | Time
----------------------------------
12 Sanjok Gurung| London | 1900
11 John | London | 1900
10 Sally | London | 1900
10 Molly | London | 1900
So the above table, Sally and Molly are term reference selected in the same node.
What I want is
Nid Speaker name | Location | Time
----------------------------------
12 Sanjok Gurung| London | 1900
11 John | London | 1900
10 Sally,Molly | London | 1900
I tried manipulating the results from views_pre_render but this method feels like it is so dirty. There should be a better clean solutions

You need to use this contrib module.
URL: https://www.drupal.org/project/views_aggregator
You can read the documentation from the below url. http://cgit.drupalcode.org/views_aggregator/plain/README.txt?id=refs/heads/7.x-1.x

This is not a view issue actually,
If you open the Manage Display of seminar content type and try to edit the display settings of entity reference FORMAT format drop-down select separator you can change what kind of separator you may want to choose from settings tab like (comma or dash)
Note: Make sure to edit the exact display mode (teaser or Full content or Default) which ever is used in the view.
May be this will resolve the issue.

Related

How to Select one address for each different country in Laravel Eloquent

I have a DB in which I have several addresses.
I need to get one row for each different country in the DB.
For example if I have
| id | name | column | country |
| -- | -------------- | ------ | ------- |
| 1 | Main address | 10 | UK |
| 2 | Second address | 3 | France |
| 3 | Third address | 78 | USA |
| 4 | Fourth address | 46 | France |
| 5 | Fifth address | 44 | France |
| 6 | Sixth address | 11 | UK |
I need to retrieve only 3 rows: 1 for UK, 1 for France and 1 for USA. The row I get for each country is not important but I need the full row. (For UK id 1 or 6 does not matter but I need all columns).
How can I do that in Laravel (preferably using Eloquent).
I cannot use group by because all columns have different values...
Depending on how big your data set is (this will get inefficient if very large) you can do something like this...
//Select and get the countries column.
$countries = DB::table('addresses')->select('country')->get();
//Get the unique values of countries from the collection
$uniqueCountries = $countries->unique();
//Array which will contain a single address from each country.
$singleAddresses = [];
//Loop over each unique country you retrieved from the database.
foreach($uniqueCountries as $country){
//Grab the first address to occur for whatever country is currently being iterated over in the loop.
$singleAddress = DB::table('addresses')->where('country','=',$country)->first();
//Push the first address found for the country into the array of single addresses from various countries.
array_push($singleAddresses,$singleAddress);
}
//Dump the array of collection to the page to make sure the output is what you want.
dump($singleAddresses);
Basically you'll want to grab only the countries column from your database through the select statement. This data is then returned to you as a collection. On that collection you can then use the unique method to get all the unique instances of country names.
Once you have your unique list of country names you can move onto grabbing an address for each country. This is done by looping over the unique set of countries one at a time. Making a database request to only select addresses where that county is, and then grab the first instance of an address within that country.
Once you have the object of that address data you'll want to push it into an array containing all the other single addresses from the countries you've retrieved.
Once the loop completes you'll have an array of Laravel collection objects with a single address from each country in your database.
Some other notes...
If you need the address to be random by country you'll want to modify your selection statement to use ->get() for all addresses from a country. Then you'll call on that data set using the collection random method to grab a random address from that country.
If your data set for these addresses and countries is extremely large you'll want to look into using the caching systems built into Laravel or lean on curated lists of data like this list of countries to help do some of the heavy listing.
I just pushed all of the address collections into an array because it was quick and easy. However Laravel does support making empty collections, which you can then use other collection methods on to manipulate your data. In my experience I've found advantages and tradeoffs to both so take that for what you will.
I managed to get what I needed using ANY_VALUE to avoid the problem of the different values and AS to be able to use the fields easily.
$addresses = Address::select(DB::raw('ANY_VALUE(name) AS name, ANY_VALUE(column) AS column'), 'country')->groupBy('country')->distinct()->get();
It gives me an array with a single row for each country.

MySQL - Searching for CC numbers

I inherited a MySQL server that has CC numbers stored in plaintext. due to PCI requirements, I need to find the numbers and mask them. The trick is they are stored in a field with other text as well. I need to find a way to search for cc numbers and change just those, not the rest of the text.
I have tried the masking feature in MySQL, but it doesn't work for this version. I also looked up a few different sites but can't seem to find anything that will really help with my particular instance.
Edit
to explain better. the previous admin didn't tell the operators to not take CC info through the live chat system. The system is using SSL but the chat history is stored in plain text in a MySQL DB. The company isn't PCI compliant (as far as getting scanned and SAQ is concerned) so we cannot have CC numbers stored anywhere. but the numbers are given in the middle of a conversation. If they were in their own column then that wouldn't be a big deal.
EDIT
I have tried using regexp to just try and search for CC #'s but now I am getting an operand error, which is lazy quantifiers I believe.
SELECT * FROM table_name Where text regexp '^4[0-9]{12}(?:[0-9]{3})?$'
Any Ideas?
You could potentially use a regular expression to search for 16-19 consecutive characters with (using LIKE if you have the numbers separated from the text, or just REGEXP):
The example is given here (where 5 is the number of items to search for, and ^$ requires it to be those at the beginning and end):
mysql> SELECT * FROM pet WHERE name REGEXP '^.{5}$';
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
Would end up something like:
REGEXP '^([0-9]{16|17|18|19})$'
https://dev.mysql.com/doc/refman/8.0/en/pattern-matching.html
And lookie here too:
Regex to match a digit two or four times

Is it possible to present / populate related data in predefined columns?

How can change the presentation of the data so I get the names o the princesses by two columns, shown in "Wanted output". Column grouping on Knight's name gives me a Princess column for each of the princesses names. I only want two columns since I know that a knight will never have more than two princesses.
The the data I get from my input source is shown below as "Input data". Unfortunately I cannot use SQL to manipulate the data, since the QUERY is based on FetchXML. The only tools I can use is what I'm getting from Reporting Services (I'm using Visual Studio 2015), so have that in mind while suggesting any solutions.
Technically thers's a 1:M relation between Knight and Princess, but there's a restriction in the system so that a knight will never have more than 2 princesess. A Knight can have 0, 1 or 2 princesses.
Input data
_________________________________
| Knight | Princess |
|_______________|_______________|
|_____Adam______|_____Anna______|
|_____Adam______|____Angelica___|
|_____Erik______|_____Erika_____|
|_____Erik______|______Eva______|
Output
_________________________________________________________________________________
| Knight | Princess 1 | Princess 2 | Princess 3 | Princess 4 |
|_______________|_______________|_______________|_______________|_______________|
|_____Adam______|_____Anna______|_____Angelica__|_______________|_______________|
|_____Erik______|_______________|_______________|_____Erika_____|_____Eva_______|
Wanted output
_________________________________________________
| Knight | Princess 1 | Princess 2 |
|_______________|_______________|_______________|
|_____Adam______|_____Anna______|___Angelica____|
|_____Erik______|_____Erika_____|_____Eva_______|
Any suggestions?
You can do this by using choose and lookupset on the dataset:
=Choose(1,LookupSet(Fields!Knight.Value,Fields!Knight.Value,Fields!Princess.Value,"InputData"))
=Choose(2,LookupSet(Fields!Knight.Value,Fields!Knight.Value,Fields!Princess.Value,"InputData"))
=Choose(3,LookupSet(Fields!Knight.Value,Fields!Knight.Value,Fields!Princess.Value,"InputData"))
etc.
In each column.
This is almost impossible, but you have lucked out by having a (quite reasonable) limit of 2 Princesses per Knight. Any more and you would be stuck.
I would use an Table, not a Matrix object for this. First column is the Knight.
The next column has a static Header "Princess 1", with expression:
=Min(Fields!Princess.Value)
The 3rd column has a static Header "Princess 2", with expression:
=Iif ( Min(Fields!Princess.Value) = Max(Fields!Princess.Value) , "" , Max(Fields!Princess.Value) )
You could make a table with a rowgroup by Knight and within that rowgroup body add a tablix with a columngroup by Princess. Only problem would be, that the column headers Princess 1..x would have to be somehow hard coded into the underlying table.

MySQL full text search matching similar results

I'll try to explain my situation: I'm trying to create a search engine for products on my website, so when the user needs to find a product I need to show similar ones, here's an example.
User searches:
assassins creed OR assassinscreed OR aSsAssIn's CreeD assuming there are no letters/numbers mispelling (those 3 queries should produce the same result)
Expected results:
Assassin's Creed AND Assassin's Creed: Unity AND Assassin's Creed: Special Edition
What have I tried so far
I have created a MySQL field for the search engine which contains a parsed name of the product (Assassin's Creed: Unity -> assassinscreedunity
I parse the search query
I search using MySQL's INSTR()
My problem
I'm fine by using this, but I heard it can be slow when the number of rows increases, I've created a full-text index in my table, but I don't think it would help, so I need another solution.
Thanks for any answer, and ask me anything before downvoting.
First of all, you should keep track of performance issues in your queries more precisely than 'heard it cand be slow' and 'think it would help'. One starting point may be the Slow Query Log.
If you have a table which contains the same parsed name in more than one row, consider normalizing your database. In the specific case, store unique parsed names in one table, and only the id of the corresponding parsed name in the table you described in your question. This way, you only need to check the smaller table with unique names and can then quickly find all matching entries in the main table by id.
Example:
Consider the following table with your structure
id | product_name | rating
-----------------------------------
1 | assassinscreedunity | 5
2 | assassinscreedunity | 2
3 | monkeyisland | 3
4 | monkeyisland | 5
5 | assassinscreedunity | 4
6 | monkeyisland | 4
you would have to scan all six entries to find relevant rows.
In contrast, consider two tables like this:
id | p_id | rating
--------------------
1 | 1 | 5
2 | 1 | 2
3 | 2 | 3
4 | 2 | 5
5 | 1 | 4
6 | 2 | 4
id | name
--------------------------
1 | assassinscreedunity
2 | monkeyisland
In this case, you only have to scan two entries (compared to six) and can then efficiently look up relevant rows using the integer id.
To further enhance the performance, you could extend the concept of a parsed name and use hashes. For example, you could calculate the SHA1-hash of your parsed name which is a 160 bit value. You can find entries in your database for this value very efficiently. To match substrings, you can add them to the second table as well. Since the hash only needs to computed once, you still can use the database to match by an integer. Another thing for you might be fuzzy hashing.
In addition, you should read up on the Rabin–Karp algorithm or string searching in general.

How do I use mysql to match against multiple possibilities from a second table?

I'm not entirely sure how to ask this question, so I'll lead by providing an example table and an example output and then follow up with a more thorough explanation of what I'm attempting to accomplish.
Imagine that I have two tables. In the first is a list of companies. Some of these companies have duplicate entries due to being imported and continuously updated from different sources. For example, the company table may look something like this:
| rawName | strippedName |
| Kohl's | kohls |
| kohls.com | kohls |
| kohls Corporation | kohls |
So in this situation, we have information that has come in from three different sources. In an attempt to allow my program to understand that each of these sources are all the same store, I created the stripped name column (which I also use for creating URL's and whatnot).
In the second table, we have information about deals, coupons, shipping offers, etc. However, since these come in from their various sources, the end up with the three different rawNames that we identified above. For example, the second table might look something like this:
| merchantName | dealInformation |
| kohls.com | 10% off everything... |
| kohl's | Free shipping on... |
| kohls corporation | 1 Day Flash Sale! |
| kohls.com | Buy one get one... |
So here we have four entries that are all from the same company. However, when a user on the site visits the listing for Kohls, I want it to display all the entries from each source.
Here is what I currently have, but it doesn't seem to be doing the trick. This seems to only work if I set the LIMIT in that sub-query to 1 so that it only brings back one of the rawNames. I need it to match against all of the rawNames.
SELECT * FROM table2
WHERE merchantName = (SELECT rawName FROM table1 WHERE strippedName = '".$strippedName."')
The quickest fix is to replace your mercahantName = with merchantName IN
SELECT * FROM table2
WHERE merchantName IN (SELECT rawName FROM table1 WHERE strippedName = '".$strippedName."')
The = operator needs to have exactly one value on each side - the IN keyword matches a value against multiple values.