MYSQL view containing a row for each element in string - mysql

I don't know if it's possible but I try to ask you.
I've a user table
|ID|production_lines|activity|
|1 | A|B|C | X|Y|Z |
|2 | B|C|D | X|Y|Z |
I need a view displaying this
|production_line|activity|count|
| A | X | 1 |
| B | X | 2 |
| C | X | 2 |
| D | X | 1 |
| A | Y | 1 |
| B | Y | 2 |
| C | Y | 2 |
| D | Y | 1 |
and so on...
The "count" columns is the count of how many time i've a combination of this particular production_line and activity.
Thank you very much

Related

Oracle 12 - How to identify duplicates with increment?

I want to differentiate duplicate values in my query by adding an increment or a count of some sort.
The idea is to concatenate my two columns to create a new unique reference.
I tried this :
SELECT
value,
COUNT(*) OVER (PARTITION BY value) value_incr
FROM table
and got the following result :
| value | value_incr |
| --- | --- |
| a | 1 |
| b | 3 |
| b | 3 |
| b | 3 |
| c | 2 |
| c | 2 |
| d | 1 |
But what I would like to get is :
| value | value_incr |
| --- | --- |
| a | 1 |
| b | 1 |
| b | 2 |
| b | 3 |
| c | 1 |
| c | 2 |
| d | 1 |
Is there a way to differentiate my duplicates in Oracle 12 ?
My best solution for now is to add a ROWNUM column, but it's not really satisfying.
Thank you

How to add a column to table results, with the number of repeats of a certain value on a row?

For example, we have a table:
| id | field | value |
|----|-------|-------|
| 1 | X | Y |
| 1 | V | Y |
| 1 | Z | W |
| 1 | Z | T |
and I want to have a following output:
| id | field | value | field_occurencies |
|----|-------|-------|-------------------|
| 1 | X | Y | 1 |
| 1 | V | Y | 1 |
| 1 | Z | W | 2 |
| 1 | Z | T | 2 |
Is there any way to do this?
Windowing functions are for that very purpose:
COUNT(*) over (partition by field) as field_occurence
We can't tell if your particular database product supports window functions (you didn't tell us)

MySql compare row values and pick one if the condition statisfied

I am trying to write a sql logic which will compare rows for a user and based on a condition it will pick one.
For eg.
+-------+------+--+
| UseId | Code | |
+-------+------+--+
| 1 | A | |
| 2 | B | |
| 3 | C | |
| 4 | D | |
| 4 | E | |
| 5 | F | |
| 5 | G | |
+-------+------+--+
The output im trying to get is, if a user has 2 records compare the code like if code =D and code=E for user 4, then retain row with code E
for user 5 , if Code=F and Code=G then retain row with code F
so the output should look like
+-------+------+--+
| UseId | Code | |
+-------+------+--+
| 1 | A | |
| 2 | B | |
| 3 | C | |
| 4 | E | |
| 5 | F | |
| | | |
+-------+------+--+

Compacting tables after normalisation

I recently increased the level of normalisation in my database, going from something like this:
+--------------------------------------+
| state_changes |
+----+-------+-----------+------+------+
| ID | Name | Timestamp | Val1 | Val2 |
+----+-------+-----------+------+------+
| 0 | John | 17:19:01 | A | X |
| 1 | Bob | 17:19:02 | E | W |
| 2 | John | 17:19:05 | E | Y |
| 3 | John | 17:19:06 | B | Y |
| 4 | John | 17:19:12 | C | Z |
| 5 | John | 17:19:15 | A | Z |
+----+-------+-----------+------+------+
To something more like this:
+-------------------------------+ +-------------------------------+
| state_changes_1 | | state_changes_2 |
+----+-------+-----------+------+ +----+-------------------+------+
| ID | Name | Timestamp | Val1 | | ID | Name | Timestamp | Val2 |
+----+-------+-----------+------+ +----+-------+-----------+------+
| 0 | John | 17:19:01 | A | | 0 | John | 17:19:01 | X |
| 1 | Bob | 17:19:02 | E | | 1 | Bob | 17:19:02 | W |
| 2 | John | 17:19:05 | E | | 2 | John | 17:19:05 | Y |
| 3 | John | 17:19:06 | B | | 3 | John | 17:19:06 | Y |
| 4 | John | 17:19:12 | C | | 4 | John | 17:19:12 | Z |
| 5 | John | 17:19:15 | A | | 5 | John | 17:19:15 | Z |
+----+-------+-----------+------+ +----+-------+-----------+------+
How could I now write a query to "compact" the two resulting tables where values are duplicated?
I want to ignore the ID field when considering row uniqueness;
I want to ignore the Timestamp when considering row uniqueness;
But fields must be sequential (under a Name,Timestamp ordering) to be considered duplicates.
The result, in this example, should be:
+-------------------------------+ +-------------------------------+
| state_changes_1 | | state_changes_2 |
+----+-------+-----------+------+ +----+-------+-----------+------+
| ID | Name | Timestamp | Val1 | | ID | Name | Timestamp | Val2 |
+----+-------+-----------+------+ +----+-------+-----------+------+
| 0 | John | 17:19:01 | A | | 0 | John | 17:19:01 | X |
| 1 | Bob | 17:19:02 | E | | 1 | Bob | 17:19:02 | W |
| 3 | John | 17:19:06 | B | | 2 | John | 17:19:05 | Y |
| 4 | John | 17:19:12 | C | | 4 | John | 17:19:12 | Z |
| 5 | John | 17:19:15 | A | +----+-------+-----------+------+
+----+-------+-----------+------+
My tables have several billion rows so I'm looking for something that takes efficiency into consideration; that said, I'm a realistic sort of person so I'm happy for the query to take an hour or two to run (including index rebuilds) if needs be.
I tried this on MySQL 5.1.58 and it seems to work with your test data.
SET #name = NULL;
SET #val1 = NULL;
UPDATE state_changes_1
SET Val1 = IF(Name=#name AND Val1=#val1, NULL, (#val1:=Val1)),
Name = (#name:=Name)
ORDER BY Name, `Timestamp`;
DELETE FROM state_changes_1 WHERE Val1 IS NULL;
Your problem is your concept of 'sequential' or consecutive duplicate doesn't exist in relational algebra so won't be able to do it in sql. You can get easily the latest timestamp of each state by doing
SELECT id, name, MAX(timestamp) ts , state FROM states
GROUP BY id, name, state
ORDER BY ts
However, you could do what you want by dumping your table into a text file and do a simple script in which ever language you are confortable with, perl, ruby python etc. Even on a million row table that could be done quiet quickly

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?
As an example, I would like to take a table such as this one:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | D |
| 2 | E |
| 2 | F |
| 3 | G |
| 3 | H |
| 3 | I |
+-------+------+
And run a query that produces results in this order:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 2 | D |
| 3 | G |
| 1 | B |
| 2 | E |
| 3 | H |
| 1 | C |
| 2 | F |
| 3 | I |
+-------+------+
Note that the table may have many rows, so I can't do the ordering in the application. (I'd obviously have a LIMIT clause as well in the query).
I'd try something like:
SET #counter = 0;
SELECT (#counter:=#counter+1)%3 as rr, grp, name FROM table ORDER by rr, grp
What you can do is create a temporary column in which you create sets to give you something like this:
+-------+------+-----+
| group | name | tmp |
+-------+------+-----+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 3 | G | 1 |
| 3 | H | 2 |
| 3 | I | 3 |
+-------+------+-----+
To learn how to create the sets, have a look at this question/answer.
Then its a simple
ORDER BY tmp, group, name
You can use MySQL variables to do this.
SELECT grp, name, #row:=#row+1 from table, (SELECT #row:=0) r ORDER BY (#row % 3);
+------+------+--------------+
| grp | name | #row:=#row+1 |
+------+------+--------------+
| 1 | A | 1 |
| 2 | D | 4 |
| 3 | G | 7 |
| 1 | B | 2 |
| 2 | E | 5 |
| 3 | H | 8 |
| 1 | C | 3 |
| 2 | F | 6 |
| 3 | I | 9 |
+------+------+--------------+