0

I'm trying to create a pivot table based on 200+ different values. A friend has prepared a working example of what I need in T-SQL but the ROW_NUMBER function isn't available in MySQL and I have been unable to translate this to do what I need.

The UniqueTally value is a count of how many distinct values for Word have appeared before this one. The example below shows that when "a" appears again in row 3, this doesn't increase the UniqueTally as it was also in row 1.

My data looks like this:

Table "Word"

| WordID     | MemberID   | Word     | UniqueTally   
| 1          | 1          | a        | 1
| 2          | 1          | b        | 2
| 3          | 1          | a        | 2
| 4          | 2          | c        | 1
| 5          | 2          | d        | 2
| 6          | 2          | e        | 3

I have 200+ Members and I'm trying to create a table that shows how the Unique count increases across all members. I.e. Aligning the UniqueTally value by Member. Word index is the row entry number for this member

| WordIndex  | UniqueTallyMember1 | UniqueTallyMember2 | etc   
| 1          | 1                  | 1        
| 2          | 2                  | 2        
| 3          | 2                  | 3        

A friend kindly generated the code I need in T-SQL :

/* Return the data */
SELECT
   [WordSpoken]
   ,[182] AS [Mem182_UniqueTally]
   ,[200] AS [Mem200_UniqueTally]
FROM (
   SELECT [WordSpoken], [MemberID], [UniqueTally]
   FROM (
          SELECT
                 ROW_NUMBER() OVER(PARTITION BY [MemberID] ORDER BY 
[WordID]) AS [WordSpoken]
                 ,[MemberID]
                 ,[UniqueTally]
          FROM [dbo].[ut_test]
          ) AS [test]
   ) AS [tbl]
PIVOT (MAX(UniqueTally) FOR MemberID IN ([182],[200])) AS [pvt]
GO

This uses only 2 MemberID values but it works in as much as aligning the Unique values. I need something similar in MySQL that also takes in the MemberID dynamically. Is this possible?

I've tried Googling and searching other similar posts about this but I'm unable to translate these directly to my problem.

danjp
  • 717
  • 1
  • 5
  • 20

1 Answers1

1

A direct way to simulate the ROW_NUMBER is by using incrementing a session variable conditionally using ORDER BY. See this example:

#DROP TEMPORARY TABLE IF EXISTS sessionVarDemo;
CREATE TABLE sessionVarDemo(memberId INT UNSIGNED);

INSERT INTO sessionVarDemo VALUES (1), (2), (3), (2), (3), (1), (2), (2), (1), (1);

SET @VMemberID := 0, @VCounter := 0;

#Ensure data is correctly ordered
#DROP TEMPORARY TABLE IF EXISTS sessionVarDemoOrdered;
CREATE TEMPORARY TABLE sessionVarDemoOrdered SELECT memberId FROM sessionVarDemo ORDER BY memberId;

SELECT @VCounter := IF(@VMemberID != memberId, 0, @VCounter + 1) rowNumber, @VMemberID := memberId memberId FROM sessionVarDemoOrdered A;

Note that this may be possible without the temp table depending on your local setup with something like this:

SELECT @VCounter := IF(@VMemberID != memberId, 0, @VCounter + 1) rowNumber, @VMemberID := memberId memberId FROM sessionVarDemo ORDER BY memberId A;

Regards,

Edit 1

If your run this code, do you get the following output with the memberid from 1-3 and the rownumber incrementing correctly?

#DROP TEMPORARY TABLE IF EXISTS sessionVarDemo;
CREATE TABLE sessionVarDemo(memberId INT UNSIGNED);

INSERT INTO sessionVarDemo VALUES (1), (2), (3), (2), (3), (1), (2), (2), (1), (1);

SET @VMemberID := 0, @VCounter := 0;

SELECT @VCounter := IF(@VMemberID != memberId, 0, @VCounter + 1) rowNumber, @VMemberID := memberId memberId FROM sessionVarDemo ORDER BY memberId A;

+-----------+----------+
| rowNumber | memberId |
+-----------+----------+
|         0 |        1 |
|         1 |        1 |
|         2 |        1 |
|         3 |        1 |
|         4 |        1 |
|         5 |        1 |
|         6 |        1 |
|         7 |        1 |
|         0 |        2 |
|         1 |        2 |
|         2 |        2 |
|         3 |        2 |
|         4 |        2 |
|         5 |        2 |
|         6 |        2 |
|         7 |        2 |
|         0 |        3 |
|         1 |        3 |
|         2 |        3 |
|         3 |        3 |
+-----------+----------+
20 rows in set (0.00 sec)

Edit 2

Here's how I'd implement the ROW_NUMBER in your friends pseudocode using session variables:

SET @VMemberID := 0, @VCounter := 0;

/* Return the data */
SELECT
   [WordSpoken]
   ,[182] AS [Mem182_UniqueTally]
   ,[200] AS [Mem200_UniqueTally]
FROM (
   SELECT [WordSpoken], [MemberID], [UniqueTally]
   FROM (
          SELECT @VCounter := IF(@VMemberID != memberId, 0, @VCounter + 1) rowNumber, @VMemberID := memberId memberId
          FROM [dbo].[ut_test]
          ORDER BY [WordSpoken]
                 ,[MemberID]
                 ,[UniqueTally]
          ) AS [test]
   ) AS [tbl]
PIVOT (MAX(UniqueTally) FOR MemberID IN ([182],[200])) AS [pvt]
GO

James

James Scott
  • 1,032
  • 1
  • 10
  • 17
  • Thanks James, although I'm not sure how to put this into the nested select in the context of the rest of the query – danjp Aug 24 '17 at 10:51
  • Added a bit to the answer, can you get back to me? – James Scott Aug 24 '17 at 11:31
  • Thanks, although each member needs a unique column. This code (without Pivot) generates the cols but not the right value. I'll keep going `SET @VMemberID := 0, @VCounter := 0; SELECT 182 AS M182_UniqueTally ,200 AS M200_UniqueTally FROM ( SELECT MemberID, UniqueTally FROM ( SELECT @VCounter := IF(@VMemberID != MemberID, 0, @VCounter + 1) UniqueTally, @VMemberID := MemberID MemberID FROM WordShort ) AS test ) AS tbl PIVOT ( MAX(UniqueTally) FOR MemberID IN (182,200) ) AS pvt` – danjp Aug 24 '17 at 11:41
  • Can you answer this specifically from my edit with the code? 'If your run this code, do you get the following output with the memberid from 1-3 and the rownumber incrementing correctly?', if I know this I can have a go modifying your query – James Scott Aug 24 '17 at 11:53
  • Yes this code gives me all the members in the same columns as per your output `SET @VMemberID := 0, @VCounter := 0; SELECT @VCounter := IF(@VMemberID != MemberID, 0, @VCounter + 1) UniqueTally, @VMemberID := MemberID MemberID FROM WordShort ORDER BY MemberID;` – danjp Aug 24 '17 at 11:59
  • the other code above isn't pulling the Tally value in, just repeating the Member ID value, but it is creating a column per Member. (this is without the PIVOT bit at the end though) – danjp Aug 24 '17 at 12:00
  • OK, added how to include the counter to your friends code – James Scott Aug 24 '17 at 12:07
  • Many thanks for your help James. It isn't working yet but I'm getting closer. – danjp Aug 24 '17 at 12:18
  • No worries, feel free to post back if you get stuck. Wrote an answer to a similar post some time ago, https://stackoverflow.com/questions/38126334/pivot-data-in-mysql-by-month/38142567#38142567 maybe the single dimension melt and cast procedure described here can help – James Scott Aug 24 '17 at 12:33
  • It looks like this is going to be easier for me to do in python / panda within a dataframe which is where I need this data to be anyway. Cheers `q1 = %sql SELECT UniqueTally FROM Word WHERE (MemberID = 98) LIMIT 100000 q2 = %sql SELECT UniqueTally FROM Word WHERE (MemberID = 228) LIMIT 100000 df1 = q1.DataFrame() df2 = q2.DataFrame() df1 = df1.rename(columns = {'UniqueTally':'Member98'}) df2 = df2.rename(columns = {'UniqueTally':'Member228'}) df1 = df1.assign(Member228=df2.values) df1` – danjp Aug 24 '17 at 12:36