I need to bring back the values in a long table as wide while preserving duplicate rows:
IE: My table:
Colname | ColValue | PK
Field1 | 12 | 1
Field2 | apple | 1
Field3 | blue | 1
Field3 | Red | 1
What I want:
PK | Field1| Field2 | Field3
1 |12 | apple |blue
1 |12 | apple |red
I can't seem to figure out how to make a pivot work in this situation as to do any max(colvalue) then removes the second Field 3 value. A dynamic column solution would be wonderful as I do not necessarily know the names of the fields/columns.
What I have:
select PK as CompPK,
ColName,
Colvalue
from test1)
Pivot(
max(colvalue) for ColNamein ('Field1' as Field1,'Field2' as Field2,'Field3' as Field3)
This returns of course just:
PK | Field1| Field2 | Field3
1 |12 | apple |blue
I do have a time stamp column and other 'random' columns on this table.
Edit:
Yes. Theoretically I want all possible iterations.
Try
select * from(
Select pk, colvalue as field1
From table1
Where colname ='Field1'
) T1
Full Join (
Select pk, colvalue as field2
From table1
Where colname ='Field2'
) T2
Using (pk)
Full join (
Select pk, colvalue as field3
From table1
Where colname ='Field3'
) T3
Using (pk)
Demo http://sqlfiddle.com/#!4/ec147/3
| PK | FIELD1 | FIELD2 | FIELD3 |
|----|--------|--------|--------|
| 1 | 12 | apple | blue |
| 1 | 12 | apple | Red |
Related
I have the table as below:
FK | Field1 | Field2 | Feild3
============================
3 | Y | N |N
3 | N | Y |N
I want the result to be like this. please help:
FK | Field1 | Field2 | Feild3
================================
3 | Y | Y | N
select fk, max(field1), max(field2)
from your_table
group by fk
Select fk, Max(field1), max(field2) from table group by fk
In this case you can just use max to return the highest value for each column.
I'm trying to compare rows between identical tables (TestTable) in two different databases (MainDB and OtherDb) to look for data differences for certain fields (Field1 in this example).
The SQL query is dynamically generated as it loops over a set of tables. Everything works great for identifying differences, but I can't tell which row came from which database.
SQL Query:
SELECT DISTINCT Field1
FROM (
SELECT Field1
FROM (
SELECT Field1
FROM [MainDB].[dbo].[TestTable]
where Field2 = 'company1'
UNION ALL
SELECT Field1
FROM [OtherDB].[dbo].[TestTable]
where Field2 = 'company1'
) UnionedTables
GROUP BY Field1
HAVING COUNT(*) < 2
) results
MainDB.dbo.TestTable:
MainDB.dbo.TestTable
+---------------+----------+
| Field1 | Field2 |
+---------------+----------+
| duplicate | company1 |
| unique maindb | company1 |
| misc data | company2 |
+---------------+----------+
OtherDB.dbo.TestTable
OtherDB.dbo.TestTable
+----------------+----------+
| Field1 | Field2 |
+----------------+----------+
| duplicate | company1 |
| unique otherdb | company1 |
| misc data | company2 |
| misc data | company3 |
| misc data | company4 |
| misc data2 | company4 |
+----------------+----------+
Current Output
+----------------+
| Field1 |
+----------------+
| unique maindb |
| unique otherdb |
+----------------+
Desired Output
+----------------+----------+
| Field1 | Database |
+----------------+----------+
| unique maindb | MainDB |
| unique otherdb | OtherDB |
+----------------+----------+
This seem like what you want. Just add the string representing the database origin to the query generation to produce this:
SELECT DISTINCT Field1, [DB]
FROM (
SELECT Field1, 'MainDB' as [DB]
FROM [MainDB].[dbo].[TestTable]
where Field2 = 'company1' AND Field1 NOT IN (SELECT Field1 FROM [OtherDB].[dbo].[TestTable] where Field2 = 'company1')
UNION ALL
SELECT Field1, 'OtherDB' as [DB]
FROM [OtherDB].[dbo].[TestTable]
where Field2 = 'company1' AND Field1 NOT IN (SELECT Field1 FROM [MainDB].[dbo].[TestTable] where Field2 = 'company1')
) as Results
You cannot use a Group By in the query without including the DB in the Group clause, which made it only unique by the DB. With this you make each data set unique, then union them, eliminating the need for the GROUP BY.
Here is my data:
| ID | FIELD1 | FIELD2 | FIELD3 |
|-------------------------------|
| 1 | NULL | value1 | value2 |
|-------------------------------|
| 2 | NULL | value3 | NULL |
|-------------------------------|
| 3 | value4 | NULL | NULL |
|-------------------------------|
| 4 | value5 | value6 | value7 |
|-------------------------------|
| .. | ... | .... | .... |
Here is what I need to select:
| ID | ID2 | FIELDX |
|-------------------|
| 1 | 10 | value1 |
| 1 | 10 | value2 |
| 2 | 20 | value3 |
| 3 | 30 | value4 |
| 4 | 40 | value5 |
| 4 | 40 | value6 |
| 4 | 40 | value7 |
| .. | .. | .... |
The order of the data doesn't really matter. What matters is that each ID appears once for every associated FIELD1,2,3... value. Please note that there are many fields. I just chose to use these three as an example.
My attempt at the solution was this query:
SELECT x.ID, a.ID2, x.FIELDX
FROM (
SELECT t.ID, t.FIELD1
FROM SCHEMA1.TABLE1 t
UNION ALL
SELECT t.ID, t.FIELD2
FROM SCHEMA1.TABLE1 t
UNION ALL
SELECT t.ID, t.FIELD3
FROM SCHEMA1.TABLE1 t
) x
JOIN SCHEMA2.TABLE2 a ON x.ID = a.ID
WHERE x.FIELDX != NULL
WITH UR;
While this does do the job, I would rather not have to add a new inner select statement for each additional field. Moreover, I feel as though there is a more efficient way to do it.
Please advise.
DB2 doesn't have an explicit unpivot and your method is fine. A more efficient method is probably to do:
SELECT id, id2, fieldx
FROM (SELECT x.ID, a.ID2,
(case when col = 'field1' then field1
when col = 'field2' then field2
when col = 'field3' then field3
end) as FIELDX
FROM SCHEMA1.TABLE1 x join
SCHEMA2.TABLE2 a
on x.ID = a.ID cross join
(select 'field1' as col from sysibm.sysdummy1 union all
select 'field2' from sysibm.sysdummy1 union all
select 'field3' from sysibm.sysdummy1
) c
) x
WHERE x.FIELDX is not NULL;
This doesn't necessarily simplify the code. It does make it easier for DB2 to optimize the joins. And it only requires reading table1 once instead of one time for each column.
As a note: you should use fieldx is not null rather than fieldx != null.
I've 2 identical tables, one will be updated and the other no, so I want to write stored procedure to check the updates for existing record in table 2 and if not exist to insert the record from table 1 to table 2.
Table 1
| Field1 | Field2 | Field3 |
| ------ | ------ | -----: |
| A | 1 | $10 |
| B | 2 | $20 |
| C | 2 | $21 |
Table 2
| Field1 | Field2 | Field3 |
| ------ | ------ | -----: |
| A | 3 | $13 |
| B | 2 | $20 |
What the stored procedure will do in this sample, it'll update row (B) in Table 2 with the data in Table 1 and insert row (C) to Table 2.
For the update part, you can check using the ID or any identifier field in your database:
UPDATE t2
SET t2.field2 = t1.field2 and t2.field3 = t1.field3
FROM table2 AS t2
INNER JOIN table1 AS t1
ON t2.field1=t1.field1
And just add the insert part from the reply above after the update statement.
Have you considered something like this?
INSERT INTO Table2
(
Field1
,Field2
,Field3
)
SELECT
Field1
,Field2
,Field3
FROM Table1
WHERE NOT EXISTS (
SELECT
Field1
,Field2
,Field3
FROM Table2
)
Of course, if you have an identity seed, then you just take the MAX(Value) instead.
I try to consolidate two rows of the same table whereas each row has a priority.
The value of interest is the value having priority 1 if it is not NULL; otherwise the value with priority 0.
An example data source could be:
| Id | GroupId | Priority | Col1 | Col2 | Col3 | ... | Coln |
-----------------------------------------------------------------
| 1 | 1 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 2 | 1 | 1 | NULL | NULL | 2.83 | ... | bar |
| 3 | 2 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 4 | 2 | 1 | 23 | NULL | 2.83 | ... | NULL |
and I want to have:
| GroupId | Col1 | Col2 | Col3 | ... | Coln |
-------------------------------------------------
| 1 | NULL | 4711 | 2.83 | ... | bar |
| 2 | 23 | 4711 | 2.83 | ... | f00 |
Is there a generic way in TSQL without the need to check each column explicitly?
SELECT
t1.GroupId,
ISNULL(t2.Col1, t1.Col1) as Col1,
ISNULL(t2.Col2, t1.Col2) as Col2,
ISNULL(t2.Col3, t1.Col3) as Col3,
...
ISNULL(t2.Coln, t1.Coln) as Coln
FROM mytable t1
JOIN mytable t2 ON t1.GroupId = t2.GroupId
WHERE
t1.Priority = 0 AND
t2.Priority = 1
Regards
I'll elaborate the ROW_NUMBER() solution that #KM suggested since IMO it's the best solution for this. (In CTE form for easier readability)
WITH cte AS (
SELECT
t1.GroupId,
t1.Col1,
t1.Col2,
ROW_NUMBER() OVER(PARTITION BY t1.GroupId ORDER BY ISNULL(GroupId ,-1) ) AS [row_id]
FROM
mytable t1
)
SELECT
*
FROM
cte
WHERE
row_id = 1
That will give you the row with the highest priority (according to your rules) for each GroupId in mytable.
ROW_NUMBER and RANK are two of my favorite TSQL tricks. http://msdn.microsoft.com/en-us/library/ms186734.aspx
edit: Another favorite of mine is PIVOT/UNPIVOT which you can use to transpose rows/columns which is another way of going about this type of problem. http://msdn.microsoft.com/en-us/library/ms177410.aspx
I think this would do what you are asking for without using isnull for every column
select
*
from
mytable t1
where
priority=(select max(priority) from mytable where groupid=t1.groupid group by groupid)