Display row of another table as column of current table - sql-server-2008

Consider there are two tables:
Table1:
**Result Total**
Pass 102
Fail 3
Undetermined 1
Table 2:
**Pass% Fail% Undetermined%**
96.23 2.83 0.94
Result Needed:
**Result Total Percentage**
Pass 102 96.23
Fail 3 2.83
Undetermined 1 0.94
How to convert the table 2 rows as column in table 1 to obtain the result ?

first, You can try to do unpivot on Table2, then JOIN with Table1.
Your sql-server version is 2008, you can use unpivot by UNION ALL.
CREATE TABLE T1(
Result VARCHAR(50),
Total int
);
CREATE TABLE T2(
Pass FLOAT,
Fail FLOAT,
Undetermined FLOAT
);
insert into T2 VALUES (96.23,2.83,0.94)
INSERT INTO T1 VALUES ('Pass',102);
INSERT INTO T1 VALUES ('Fail',3);
INSERT INTO T1 VALUES ('Undetermined',1);
Query 1:
SELECT t1.*,s.val
FROM (
SELECT Pass val,'PASS' Name
FROM T2
UNION ALL
SELECT Fail val,'Fail' Name
FROM T2
UNION ALL
SELECT Undetermined val,'Undetermined' Name
FROM T2
) s inner join T1 t1 on t1.Result = s.Name
Results:
| Result | Total | val |
|--------------|-------|-------|
| Pass | 102 | 96.23 |
| Fail | 3 | 2.83 |
| Undetermined | 1 | 0.94 |
If you can use CROSS APPLY with VALUE you can try this.
Query:
SELECT t1.*,s.val
FROM (
SELECT v.* FROM T2
CROSS APPLY(VALUES
(Pass,'PASS'),
(Fail,'Fail'),
(Undetermined,'Undetermined')
) v(val,Name)
) s inner join T1 t1 on t1.Result = s.Name
Results:
| Result | Total | val |
|--------------|-------|-------|
| Pass | 102 | 96.23 |
| Fail | 3 | 2.83 |
| Undetermined | 1 | 0.94 |

Related

Select duplicated values from one coloum and get there value in one row

i have table with 2 columns like below
+----------+----------+
| Column A | Column B |
+----------+----------+
| 123 | ABC |
| 123 | XYC |
| 123 | FGH |
| 145 | QWE |
| 147 | YUI |
+----------+----------+
I want to select all values from table but view it like below:
+----------+---------+---------+----------+
| Column A | value 1 | value 2 | value 3 |
+----------+---------+---------+----------+
| 123 | ABC | XYC | FGH |
| 145 | QWE | | |
| 147 | YUI | | |
+----------+---------+---------+----------+
If you're not trying to create extra columns in your output, you can simply use GROUP_CONCAT with the separator of your choice. For example:
SELECT `Column A`,
GROUP_CONCAT(`Column B` SEPARATOR ' | ') AS `Values`
FROM table1
GROUP BY `Column A`
Output:
Column A Values
123 ABC | XYC | FGH
145 QWE
147 YUI
Demo on dbfiddle
I'm not sure how are you going to execute the query? but if you can manage to create dynamic SQL query string to find all duplicates rows and insert each row into a temp table and other values (unique) into a separate temp table. Then create another query to join all temp tables (with duplicate) value into a new data set, union all of them with the (unique) data set.
It may be a long and not a good solution but here's my experiment:
Insert all duplicates rows into #temp tables (3 rows= 3 #temp tables)
SELECT Id,Name
INTO #temp1
FROM TestTable
WHERE Name='ABC'
SELECT Id,Name
INTO #temp2
FROM TestTable
WHERE Name='XYC'
SELECT Id,Name
INTO #temp3
FROM TestTable
WHERE Name='FGH'
Insert all unique rows into single #temptable
SELECT Id,Name
INTO #temp4
FROM TestTable
WHERE Id!=123
Query
SELECT t1.Id,t1.Name as Value1,t2.Name as Value2,t3.Name as Value3
FROM #temp1 t1
INNER JOIN #temp2 t2 on t1.Id=t2.Id
INNER JOIN #temp3 t3 on t1.Id=t3.Id
UNION ALL
SELECT t4.Id,t4.Name as Value1,null as Value2,null as Value3
FROM #temp4 t4
Result
If you want three different columns, you can use row_number() and conditional aggregation:
select a,
max(case when seqnum = 1 then b end) as b_1,
max(case when seqnum = 2 then b end) as b_2,
max(case when seqnum = 3 then b end) as b_3
from (select t.*,
row_number() over (partition by a order by b) as seqnum
from t
) t
group by a;

Odd behavior of max and having in MySQL when max==0

I have the following table:
mysql> select * from foo;
| id | value | bar |
+----+-------+------+
| 1 | 2 | 3 |
| 2 | 0 | 3 |
| 1 | 1 | 5 |
I want to select the tuple with the maximum value for each id. However, when max(value) is 0, I don't get a result.
mysql> select id,max(value),bar from foo group by id having max(value);
| id | max(value) | bar |
+----+------------+------+
| 1 | 2 | 3 |
Is this supposed to behave like that and if so, why?
HAVING cannot be used in any way to pick a record out of a group of records as defined by the fields used in the GROUP BY clause. It is rather applied to the group as a whole.
So, in your case, you have to do a self-join to get the rest of the table fields:
select t1.id, t1.value, t1...
from foo as t1
join (
select id, max(value) as max_value
from foo
group by id
) as t2 on t1.id = t2.id and t1.value = t2.max_value
IMHO you can get MAX couple by multiplying (id x value).
create table foo(id int, value int);
insert into foo values
(2,0),
(1,0),
(2,1),
(3,0),
(2,2);
select id, value
from foo
order by (id * value) desc
limit 1;
id | value
2 | 2
drop table foo;

Query for looping values in column

I need to make a query that moves values of only one column one row up ↑ at a time:
+------------+----------------+
| anotherCOL | values_to_loop |
+------------+----------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
| 10 | 10 |
+------------+----------------+
So, the next time i run the query, it should look like this
+------------+----------------+
| anotherCOL | values_to_loop |
+------------+----------------+
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
| 5 | 6 |
| 6 | 7 |
| 7 | 8 |
| 8 | 9 |
| 9 | 10 |
| 10 | 1 |
+------------+----------------+
I need to loop the values of only one MYSQL COLUMN, as in move the values one ROW UP ↑ each time I run the query.
Notice: Tables provided are just illustrative, the data is different.
Here's how you can do it within a single UPDATE query:
UPDATE tbl a
INNER JOIN (
SELECT values_to_loop
FROM (SELECT * FROM tbl) c
ORDER BY anotherCOL
LIMIT 1
) b ON 1 = 1
SET a.values_to_loop =
IFNULL(
(SELECT values_to_loop
FROM (SELECT * FROM tbl) c
WHERE c.anotherCOL > a.anotherCOL
ORDER BY c.anotherCOL
LIMIT 1),
b.values_to_loop
)
It works as follows:
Updates all records from tbl
Joins with a temporary table to retrieve the top value of values_to_loop (the one that will go to the bottom)
Set the new value for values_to_loop to the corresponding value from the next row (c.anotherCOL > a.anotherCOL ... LIMIT 1)
Notes:
This works even if there are gaps in anotherCOL (eg: 1, 2, 3, 6, 9, 15)
It is required to use (SELECT * FROM tbl) instead of tbl because you're not allowed to use the table that you're updating in the update query
Faster query when there are no gaps in anotherCOL
If there are no gaps for values in anotherCOL you can use the query below that should work quite fast if you have an index on anotherCOL:
UPDATE tbl a
LEFT JOIN tbl b on b.anotherCOL = a.anotherCOL + 1
LEFT JOIN (
SELECT values_to_loop
FROM tbl
WHERE anotherCOL = (select min(anotherCOL) from tbl)
) c ON 1 = 1
SET a.values_to_loop = ifnull(
b.values_to_loop,
c.values_to_loop
)
I`ve created a sample table and added both a select to get the looped values and update to loop the values in the table. Also, using a #start_value variable to know the "1" which might be other. Try this:
CREATE TEMPORARY TABLE IF NOT EXISTS temp_table
(other_col INT, loop_col int);
INSERT INTO temp_table (other_col, loop_col) VALUES (1,1);
INSERT INTO temp_table (other_col, loop_col) VALUES (2,2);
INSERT INTO temp_table (other_col, loop_col) VALUES (3,3);
INSERT INTO temp_table (other_col, loop_col) VALUES (4,4);
INSERT INTO temp_table (other_col, loop_col) VALUES (5,5);
DECLARE start_value INT;
SELECT start_value = MIN(loop_col) FROM temp_table;
SELECT T1.other_col, ISNULL(T2.loop_col, start_value)
FROM temp_table T1
LEFT JOIN temp_table T2
ON T1.loop_col = T2.loop_col - 1;
UPDATE T1 SET
T1.loop_col = ISNULL(T2.loop_col, #start_value)
FROM temp_table T1
LEFT JOIN temp_table T2
ON T1.loop_col = T2.loop_col - 1;
SELECT *
FROM temp_table;
Let me know if it works for you.
Step by step:
1 - created a temp_table with values 1 to 5
2 - declared a start_value which will keep the lowest value for the column you to need to loop through
3 - select all rows from temp_table self left join with same temp_table. join condition is on loop_col - 1 so it can shift the rows up
4 - the same self left join, but this time update the values in place too.
please note that in case i get a null value, it should be the start_value there, because it cannot match
Perhaps these are what you had in mind:
update T
set values_to_loop = mod(values_to_loop, 10) + 1
update T
set values_to_loop =
coalesce(
(
select min(t2.values_to_loop) from T t2
where t2.values_to_loop > T.values_to_loop
),
(
select min(values_to_loop) from T
)
)

copy from t1 into new table t2 filtering out duplicate rows

I have a table t1, some rows have duplicates in all columns EXCEPT id.
t1's id is AUTO_INCREMENT and has 1MIL rows.
t2 is a new table without data and the id does not need AUTO_INCREMENT as i will probably create a new column for this.
Q: After i create t2, how can i copy from t1 into t2 where distinct values from t1 in all columns, so that t2 has no duplicate rows
I am on amazons RDS ENGINE=InnoDB
t1 - this is what i have
+---+-----+-----+------+-------+
|id |fname|lname|mytext|morevar|
|---|-----|-----|------|-------|
| 1 | joe | min | abc | 123 |
| 2 | joe | min | abc | 123 |
| 3 | mar | kam | def | 789 |
| 4 | kel | smi | ghi | 456 |
+------------------------------+
t2 - this is what i would like to end up with
+---+-----+-----+------+-------+
|id |fname|lname|mytext|morevar|
|---|-----|-----|------|-------|
| 1 | joe | min | abc | 123 |
| 3 | mar | kam | def | 789 |
| 4 | kel | smi | ghi | 456 |
+------------------------------+
this is my attempt, but got: Error Code: 1136. Column count doesn't match value count at row 1
INSERT INTO t2 (id,fname,lname,mytext,morevar)
SELECT DISTINCT st.mytext
FROM t1 st
WHERE st.id>0
AND st.id<=1000
The easiest way is to use group by:
INSERT INTO t2 (id,fname,lname,mytext,morevar)
SELECT id,fname,lname,mytext,morevar
FROM t1 st
WHERE st.id>0 AND st.id<=1000
group by mytext;
However, technically, this is not correct because the column values are not guaranteed to come from the same row. So, the right way is:
INSERT INTO t2 (id,fname,lname,mytext,morevar)
SELECT st.id, st.fname, st.lname, st.mytext, st.morevar
FROM t1 st join
(select mytext, min(id) as minid
from t1
group by mytext
) mint
on st.id = minid
WHERE st.id>0 AND st.id<=1000 ;
Use GROUP BY to make just that column distinct.
INSERT INTO t2 (id,fname,lname,mytext,morevar)
SELECT id, fname, lname, mytext, morevar
FROM t1 st
WHERE st.id>0
AND st.id<=1000
GROUP BY mytext
If the other columns differ between the duplicates, it will pick values from them arbitrarily (not necessarily from the same rows, even).
Try this code, it will select the smallest id number of duplicates and takes into account all columns.
INSERT INTO t2 (id,fname,lname,mytext,morevar)
SELECT min(id) id, fname, lname, mytext, morevar
FROM t1
WHERE t1.id > 0 and t1.id <= 1000
GROUP BY fname, lname, mytext, morevar
ORDER BY id;

MySQL: Merge two different tables without JOIN or UNION

I need to merge two tables:
Both have a primary key-column date, but with different values (different time intervals).
Both have different (unknown) columns: I don't know the names of the columns (same column-name may occur in both tables), I don't know how many columns, but all of the same type.
An example:
table1
date | colA | colB | colC
2011-02-02 | 1.09 | 1.03 | 1.04
table2
date | col1 | col2 | col3 | col4
2011-02-03 | 1.03 | 1.02 | 1.07 | 1.03
the result of the query should look like this:
tableResult
date | colA | colB | colC | col1 | col2 | col3 | col4
2011-02-02 | 1.09 | 1.03 | 1.04 | null | null | null | null
2011-02-03 | null | null | null | 1.03 | 1.02 | 1.07 | 1.03
This will not work:
INNER JOIN because it will only return the intersection between table1 and table2,
OUTER JOIN returns intersection + values only from left table (or right table if right join is used)
UNION because the count of columns may differ.
Any Ideas?
Christoph
You can create a temp table with the union of just the date column, and then use the temp table to left outer join with the other 2.
Example:
DROP TABLE temptbl IF EXISTS;
CREATE TEMPORARY TABLE temptbl (myDate DATETIME PRIMARY KEY)
AS (SELECT MyDate FROM table1)
UNION (SELECT MyDate FROM table2)
ORDER BY MyDate;
SELECT * FROM temptbl
LEFT OUTER JOIN table1 USING (MyDate)
LEFT OUTER JOIN table2 USING (MyDate);
select coalesce(t2.data,'')+coalesce(t1.data,'') as data,
t2.col1, t2.col2, t2.col3 ,t2.col4 ,t1.cola ,t1.colb, t1.colc
from table2 as t2
full outer join
table1 t1
on t2.data = 2011-02-03
or t1.data = 2011-02-02