MySQL - Join tables and convert rows to columns - mysql

I have two tables similar to these (t_stamp would normally be a DATETIME, abbreviated here for clarity):
datapoints
+------+---------+----+---------+
| ndx | value | ID | t_stamp |
+------+---------+----+---------+
| 1 | 503.42 | 1 | 3/1/15 |
| 2 | 17.81 | 2 | 3/1/15 |
| 4 | 498.21 | 1 | 3/2/15 |
| 4 | 19.51 | 2 | 3/2/15 |
+------+---------+----+---------+
parameters
+------+----+---------------+-------+
| ndx | ID | description | unit |
+------+----+---------------+-------+
| 1 | 1 | wetwell level | ft |
| 2 | 2 | effluent flow | MGD |
+------+----+---------------+-------+
I'm looking to combine them so that the descriptions become column headers and list the values in order of time stamp, end result looking something like this:
new table
+---------+---------------+---------------+
| t_stamp | wetwell level | effluent flow |
+---------+---------------+---------------+
| 3/1/15 | 503.42 | 17.81 |
| 3/2/15 | 498.21 | 19.51 |
+---------+---------------+---------------+
Bearing in mind, I have considerably more rows in each table so I'm looking for something dynamic. It could be query or stored procedure based. Thank you for any help!

Related

Update one column based on matching values of two columns from the same table

Basically I have 3 columns, like this:
+-------------+-------------+--------+
| startpoint | endpoint | number |
+-------------+-------------+--------+
| 15037232632 | 4226861620 | null |
| 4226862003 | 4226862079 | null |
| 4226862079 | 4226862111 | null |
| 4226862111 | 4226862121 | 2 |
| 4226862121 | ---------- | 1 |
| 15025374738 | 4226862003 | null |
| 4226861620 | 15025374738 | null |
| 4226801794 | 15037232632 | null |
+-------------+-------------+--------+
What I am trying to do is:
Step 1 : I assign a number '1' to any one of the IDs from the 'startpoint' column
Step 2 : Match the 'startpoint' ID to which I assigned the number in the previous step with the IDs in the 'endpoint' column
Step 3 : After the 'startpoint' ID matches with the 'endpoint' ID, I assign the number 2 in the 'number' column on the ROW where the endpoint matched
Step 4: On the row where number was assigned, I take the 'startpoint' ID and then repeat the steps 2-4 again.
I have tried playing around with the update query but it doesn't seem right. Any help would be appreciated.
EDIT:
I am also including the expected output. The table without applying any queries is given above
+-------------+-------------+--------+
| startpoint | endpoint | number |
+-------------+-------------+--------+
| 15037232632 | 4226861620 | 7 |
| 4226862003 | 4226862079 | 4 |
| 4226862079 | 4226862111 | 3 |
| 4226862111 | 4226862121 | 2 |
| 4226862121 | ---------- | 1 |
| 15025374738 | 4226862003 | 5 |
| 4226861620 | 15025374738 | 6 |
| 4226801794 | 15037232632 | 8 |
+-------------+-------------+--------+

Creating a view in MySQL with columns created from row data in a table?

I've got a MySQL database containing three tables. The database contains information about various electrical and mechanical components. It has three tables.
Tables:
componentSource - contains information about where the information in the database was sourced from.
component - contains part number information, description, etc. Multiple entries will refer to a single entry in the componentSource table as its source (Each source file describes multiple components).
componentParams - contains parametric information about the components. Multiple parameter entries will refer to a single entry the component table (each component has multiple parameters).
See simplified example tables...
Database Tables and Relationships:
+-------------------------------+
| Table: componentSource |
+-------------------------------+
| compSrcID* | sourceFile |
+-------------------------------+
| 1 | comp1.txt |
| 2 | comp2.txt |
| 3 | comp3.txt |
+-------------------------------+
^
|
+---------------------------------------------------+
( many to one reference) |
^
^
+---------------------------------------------------------------+
| Table: component |
+---------------------------------------------------------------+
| compID* | partNum | mfrPartNum | mfr | compSrcID |
+---------------------------------------------------------------+
| 1 | 1234 | ABCD | BrandA | 1 |
| 2 | 2345 | BCDE | BrandB | 1 |
| 3 | 3456 | CDEF | BrandC | 3 |
| 4 | 4567 | DEFG | BrandD | 2 |
+---------------------------------------------------------------+
^
|
+---------------+ (many to one reference)
|
^
^
+-------------------------------------------------------+
| Table: componentParams |
+-------------------------------------------------------+
| compParamID* | compID | paramName | paramValue |
+-------------------------------------------------------+
| 1 | 1 | ParamA | 50 |
| 2 | 1 | ParamB | 123 |
| 3 | 1 | ParamC | 10% |
| 4 | 1 | ParamD | 0.5 |
| 5 | 1 | ParamE | Active |
| 6 | 2 | ParamA | 25 |
| 7 | 2 | ParamB | 10K |
| 8 | 2 | ParamC | 5% |
| 9 | 2 | ParamD | 0.25 |
| 10 | 2 | ParamE | Proto |
| 11 | 3 | ParamA | 53.6 |
| 12 | 3 | ParamE | Active |
| 13 | 4 | ParamY | 123-56 |
| 14 | 4 | ParamZ | True |
+-------------------------------------------------------+
I would like to create a view of the database that merges information from the three tables. I would like to have a row for each line in the component table that merges the relevant lines from the componentSource table, and all of the relevant parameters out of the componentParams table.
See example view...
Database View:
+-------------------------------------------------------------------------------------------------------------------------------------------------------+
| View: componentView |
+-------------------------------------------------------------------------------------------------------------------------------------------------------+
| compID* | partNum | mfrPartNum | mfr | SourceFile | ParamA | ParamB | ParamC | ParamD | ParamE | ParamY | ParamZ |
| 1 | 1234 | ABCD | BrandA | comp1.txt | 50 | 123 | 10% | 0.5 | Active | | |
| 2 | 2345 | BCDE | BrandB | comp1.txt | 25 | 10K | 5% | 0.25 | Proto | | |
| 3 | 3456 | CDEF | BrandC | comp3.txt | 53.6 | | | | Active | | |
| 4 | 4567 | DEFG | BrandD | comp2.txt | | | | | | 123-56 | True |
+-------------------------------------------------------------------------------------------------------------------------------------------------------+
Since I want a line in the view for each component in the component table, I think merging the info from the componentSource table is fairly straight forward with a join, but the tricky part is creating columns in the view that correspond to the value in componentParam.paramName column. Seems like this requires some recursion to read all parameters associated with a component. Also note that not all components have all the same parameters in the parameter table, so the values for the parameters not used by a component would be null.
An alternative to creating a view, if that can't be done, would be to build another database table.
My SQL skills are super rusty, and were probably not up to this task when they were fresh.
Is it possible to create a view that creates columns that are based on row data (paramName) in a table? Could you show an example?
If not, can a table be built that does the same? Again, could you show an example?
Many thanks.
Conditional aggregation can do the pivoting for you
SELECT cp.compID,
ct.partNum,
ct.mfrPartNum,
ct.mfr,
cs.SourceFile,
MAX(CASE WHEN cp.paramName = 'ParamA' THEN cp.ParamValue END) as ParamA,
MAX(CASE WHEN cp.paramName = 'ParamB' THEN cp.ParamValue END) as ParamB,
MAX(CASE WHEN cp.paramName = 'ParamC' THEN cp.ParamValue END) as ParamC,
MAX(CASE WHEN cp.paramName = 'ParamD' THEN cp.ParamValue END) as ParamD,
MAX(CASE WHEN cp.paramName = 'ParamE' THEN cp.ParamValue END) as ParamE,
MAX(CASE WHEN cp.paramName = 'ParamY' THEN cp.ParamValue END) as ParamY,
MAX(CASE WHEN cp.paramName = 'ParamZ' THEN cp.ParamValue END) as ParamZ
FROM componentParameters cp
JOIN component ct ON cp.compId = ct.compId
JOIN componentSource cs ON cs.compSrcID = ct.compSrcID
GROUP BY cp.compID,
ct.partNum,
ct.mfrPartNum,
ct.mfr,
cs.SourceFile
It is also possible to use subqueries for this, however, I guess this should do the job better.

Divide timestamp in MySQL

I have a question regarding time in MySQL.
How do i get a time stamp like this:
2014-12-07 12:54:42.000000
To correctly insert itself in this table:
The timestamp has to divide to,Hour,Dayname,Weeknumber,Daynumber
I need a fixed value of 1 in every layar of the table
+-------------+----------+--------+-----+-----+-----------x
| fixedval | Hour | Dayname| Weeknumber| Daynumber |
+-------------+----------+--------+-----------+-----------+
| 1 | | | | |
| 1 | | | | |
| 1 | | | | |
| 1 | | | | |
| 1 | | | | |
+-------------+----------+--------+-----------+-----------+
There are functions for that
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html
Insert into table
(fixedval,hour,dayname,weeknumber,daynumber)
(Select 1, hour(inputdate), dayname(inputdate), weekofyear(inputdate), dayofyear(inputdate))
SELECT HOUR(your_date) as Hour,DAYNAME(your_date) as Dayname,WEEK(your_date) as Weeknumber, DAYOFMONTH(your_date) as datenumber from table.
NOTE: You can use either DAYOFMONTH/DAYOFWEEK for day number.

Finding MAX Date of Two Fields in an Access Query

In my access database, we keep track of two sets of dates. One set is for date of membership dues payments, the other set is date of other contributions (a non-membership donation.) There are multiple dates for each person depending on number of payments made for each type.
Example:
+----+---------------+---------------+
| ID | Dues_Date | Cont_Date |
+----+---------------+---------------+
| 1 | 01/01/15 | 09/12/11 |
| | 01/01/14 | |
| | 01/01/13 | |
| 2 | 07/30/14 | 06/20/13 |
| | | 11/12/11 |
+----+---------------+---------------+
First I needed to know the most recent payment for each of the two fields so I ran a query that tells me the MAX (most recent) date for each field.
Example Query:
+----+---------------+---------------+
| ID | Max Dues_Date | Max Cont_Date |
+----+---------------+---------------+
| 1 | 01/01/15 | 09/12/11 |
| 2 | 07/30/14 | 06/20/13 |
| 3 | 02/11/13 | 09/16/14 |
| 4 | 07/30/12 | 06/20/11 |
| 5 | 12/13/13 | 11/12/14 |
+----+---------------+---------------+
Now I need a third field in the same query to compare the results of the first two fields and show which is the MAX of those two.
I have column 2 and 3 in the query; how can I take that and create column 4 in the same query?
Example Query:
+----+---------------+---------------+-----------------+
| ID | Max Dues_Date | Max Cont_Date | Max Date(DD&CD) |
+----+---------------+---------------+-----------------+
| 1 | 01/01/15 | 09/12/11 | 01/01/15 |
| 2 | 07/30/14 | 06/20/13 | 07/30/14 |
| 3 | 02/11/13 | 09/16/14 | 09/16/14 |
| 4 | 07/30/12 | 06/20/11 | 07/30/12 |
| 5 | 12/13/13 | 11/12/14 | 11/12/14 |
+----+---------------+---------------+-----------------+
Try adapting this to your own scenario:
SELECT tblTest.DueDate, tblTest.ContDate, [DueDate]-[ContDate] AS Test, IIf([Test]<0,[ContDate],[DueDate]) AS MaxRes
FROM tblTest;
"Test" finds which is the later date, ContDate or Due Date. The IIf statement selects the later date.
Does this help?

Subtract values from line above the current line in MySQL

I've the following table:
| id | Name | Date of Birth | Date of Death | Result |
| 1 | John | 3546565 | 3548987 | |
| 2 | Mary | 5233654 | 5265458 | |
| 3 | Lewis| 6546876 | 6548752 | |
| 4 | Mark | 6546546 | 6767767 | |
| 5 | Steve| 6546877 | 6548798 | |
And I need to do this for the whole table:
Result = 1, if( current_row(Date of Birth) - row_above_current_row(Date of Death))>X else 0
To make things easier, I guess, I created the same table above but with 2 extra id fields: id_minus_one and id_plus_one
Like this:
| id | id_minus_one | id_plus_one |Name | Date_of_Birth | Date_of_Death | Result |
| 1 | 0 | 2 |John | 3546565 | 3548987 | |
| 2 | 1 | 3 |Mary | 5233654 | 5265458 | |
| 3 | 2 | 4 |Lewis| 6546876 | 6548752 | |
| 4 | 3 | 5 |Mark | 6546546 | 6767767 | |
| 5 | 4 | 6 |Steve| 6546877 | 6548798 | |
So my approach would be something like (in pseudo code):
for id=1, ignore result. (Because there is no row above)
for id=2, Result = 1 if( (Where id=2).Date_of_Birth - (where id_minus_one=id-1).Date_of_Death )>X else 0
for id=3, Result = 1 if( (Where id=3).Date_of_Birth - (where id_minus_one=id-1).Date_of_Death)>X else 0
and so on for the whole table...
Just ignore id_plus_one if there is no need for it, I'll use it later for the same thing. So, if I manage to do this for id_minus_one I'll manage for id_plus_one as they are the same algorithm.
My question is how to pass that pseudo code into SQL code, I can't find a way to relate both ids in just one select.
Thank you!
As you describe this, it is just a self join with some logic on the select:
select t.*,
((t.date_of_birth - tprev.date_of_death) > x) as flag
from t left outer join
t tprev
on t.id_minus_one = tprev.id