SQL PIVOT not as suspected - sql

I'm working on a data extraction of multiple tables for so far i have this
Table A
ID
value
1
123
Table B
ID
FileID
FieldID
A_ID
Data
1
1
1
1
abc
2
1
2
1
123
3
1
3
1
TRUE
4
1
1
2
def
5
1
2
2
456
6
1
3
2
FALSE
so far I have
SELECT Id, Plate, [1] as field1, [2] as field2, [3] as field3 FROM
(SELECT A.Id, A.value , B.Data as datavalue, B.Id as dataid
FROM TableA A, TableB B
WHERE A.Id = B.A_ID)as P
PIVOT (MAX(dataid) FOR datavalue in ([1],[2],[3])) as PVT
the answer I expect
Id
Value
Field1
Field2
Field3
1
123
abc
123
TRUE
the answer I get
Id
Value
Field1
Field2
Field3
1
123
NULL
NULL
NULL
what am i missing
can't get it figured out

You need to LEFT JOIN from:
Table B to Table A
instead of
Table A to Table B
Switch the two tables around within the nested select.

Use Group by and Max function and change pivot code to :
PIVOT (MAX(datavalue) FOR datavalue in ([abc],[123],[TRUE])) AS PVT
SELECT Id,
value,
max([abc]) as field1,
max([123]) as field2,
max([TRUE]) as field3
FROM
(SELECT A.Id, A.value , B.Data AS datavalue, B.Id AS dataid
FROM TableA A, TableB B
WHERE A.Id = B.A_ID) AS P
PIVOT (MAX(datavalue) FOR datavalue in ([abc],[123],[TRUE])) AS PVT
GROUP BY id,value
Demo in db<>fiddle

I believe you meant B.FieldId instead of B.Id. Other than that you need slight modification (you got the dataId and dataValue wrong, it would be
... Max(datavalue) for dataId in ...
instead of
... Max(dataId) for dataValue in ...
Here is revised version:
SELECT
ID, PVT.value, [1] AS field1, [2] AS field2, [3] AS field3
FROM
(
SELECT
A.ID, A.value, B.Data AS datavalue, B.FieldId AS dataid
FROM TableA A
INNER JOIN TableB B ON A.ID=B.A_ID
) AS P
PIVOT(MAX(datavalue)
FOR dataid IN([1], [2], [3])
) AS PVT;
Here is DBFiddle demo.

Related

SQL - Update Rows from a list of values

So Table Setup is:
Column1 Column2 Column3
A 1 Null
B 2 Null
C 1 Null
D 2 Null
E 1 Null
F 2 Null
G 1 Null
H 2 Null
I would like to update Column3 with an array of values (Value1, Value2, Value3) and cycle through that list until the update is complete
The ultimate goal is for the table to look like this:
Column1 Column2 Column3
A 1 Value1
B 2 Value2
C 1 Value3
D 2 Value1
E 1 Value2
F 2 Value3
G 1 Value1
H 2 Value2
I originally tried in powershell but it was not working as I would have liked because of how the data is being imported, so now I am looking towards SQL. Any suggestions would be great!
You could try an update join here. The approach below is to assign an ordered sequence to both your original table and the "array" of values for updating. We join using modulus logic, such that your table's sequence ordering will match up the values in the array and will wrap around until all values have been assigned.
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY Column1) rn
FROM yourTable
)
UPDATE t1
SET Column3 = t2.val
FROM cte t1
INNER JOIN
(
SELECT 1 AS id, 'Value1' AS val UNION ALL
SELECT 2, 'Value2' UNION ALL
SELECT 3, 'Value3'
) t2
ON t2.id = 1 + ((t1.rn - 1) % 3);
Demo
Assuming you can put the "array" in a table, you can use something like this:
with vals as (
select v.*,
row_number() over (order by (select null)) - 1 as seqnum,
count(*) over () as cnt
from (values ('Value1'), ('Value2'), ('Value3')) v(val)
)
update t
set t.column3 = v.val
from (select t.*,
row_number() over (order by column1) - 1 as seqnum
from t
) t join
vals v
on t.seqnum % v.cnt = v.seqnum;
The basic idea is to enumerate the rows in each table and then use modulo arithmetic to match them.

Query for finding duplicate records where 2nd field is different

Probably very simple but given data of
TableA
FIELD1 | FIELD2
A | 1
A | 1
A | 2
B | 3
B | 3
C | 4
C | 5
How can I find the duplicate of Field 1 where Field 2 is different.
e.g from data above I want to return records 3 (A2) and 6 (C5)
Thanks in advance
You can use the following:
SELECT t1.* FROM table_name t1 INNER JOIN (
SELECT FIELD1, MIN(FIELD2) AS FIELD2
FROM table_name
GROUP BY FIELD1
) t2 ON t1.FIELD1 = t2.FIELD1 AND t1.FIELD2 <> t2.FIELD2
demo on dbfiddle.uk
You can use exists:
select a.*
from tableA a
where a.field2 > (select min(a2.field2)
from tableA a2
where a2.field1 = a.field1
);
You could also use window functions:
select a.*
from (select a.*,
min(a.field2) over (partition by field1) as min_field2
from tableA a
) a
where field2 > min_field2;

Select a record having null if the id has only one record and select not null value when the id has more than one record

I want to get a record having null if the id has only one record and select not null value when the id has more than one record
Below is example sample.
Id Field1 Field2
1 Null 34
1 Yes 52
2 Null 56
3 No 46
and output
Id Field1 Field2
1 Yes 52
2 Null 56
3 No 46
How it can be done using sql query?
Use the below query for 2008+ versions of sql server.
;with cte_1
As
( select *, count(1) over (partition by id order by id) Cnt
From YourTable)
Select Id,Field1,Field2
From Cte_1
Where Field1 is null and Cnt=1
UNION
Select Id,Field1,Field2
From YourTable
Where field1 is not null
Sample output :
Use the below query for 2005 version.
SELECT t.Id,Field1,Field2
FROM #T t
JOIN (select ID, count(ID) CntId
From #t
GROUP BY ID
HAVING COUNT(ID)=1)t1 on t.ID=t1.ID
WHERE t.Field1 is null
UNION
SELECT Id,Field1,Field2
FROM #T
WHERE Field1 is NOT NULL
ORDER BY ID
Sample output :
It sounds like you can only have one or two rows per group and one of them must have the null. Using those assumptions you can get away with a simple query.
select
Id,
min(Field1) as Field1,
coalesce(min(case when Field1 is not null then Field2 end), min(Field2)) as Field2
from T
group by Id
It also makes a minor assumption that Field2 isn't nullable. Actually it's a little more subtle than that but there's a workaround if you need it.
A solution using exists and a subquery is another option:
select * from T t1
where Field is not null or not exists (
select 1 from T t2
where t2.Id = t1.Id and t2.Field is not null
)
Use this code:
Select Distinct ID,
(Select Max(Field1) From Table1 Where ID=Tbl1.ID) as Field1,
(Select Max(Field1) From Table1 Where ID=Tbl1.ID) as Field2
From Table1 as Tbl1
Result:
ID Field1 Field2
----------- ---------- -----------
1 Yes 52
2 NULL 56
3 No 46
(3 row(s) affected)
Also below code get same result:
Select Distinct ID,
(Select Top 1 Field1 From Table1 Where ID=Tbl1.ID Order By Field1 Desc) as Field1,
(Select Top 1 Field2 From Table1 Where ID=Tbl1.ID Order BY field1 Desc) as Field2
From Table1 as Tbl1

SQL Server : join all left table and repeat right

I have to join tables in a following way:
Table A:
1
2
3
4
5
Table B:
A
B
The result table should be:
1 A
2 B
3 A
4 B
5 A
Do you have any ideas how to do this?
Assuming worst case, the column in table A is not a sequence without gaps and the number of rows in table B is not known in advance, you must apply a ROW_NUMBER on both tables and then join on a MODULO:
SELECT col1, col2
FROM
(
SELECT col1,
ROW_NUMBER() OVER (ORDER BY col1) -1 AS rn
FROM tableA
) AS A
JOIN
(
SELECT col2,
ROW_NUMBER() OVER (ORDER BY col2) -1 AS rn
FROM tableB
) AS B
ON A.rn % (SELECT COUNT(*) FROM tableB) = B.rn
Maybe something like this:
select A.nr, case when (A.nr%2=0) then b2.chr else b3.chr end letter
from A, B b2, B b3
where b2.chr = 'A' and b3.chr = 'B'

How to select [ParentName] from the same table based on [ParentId]

I have a table structure like so (simplified):
Id ParentId Name Desc
------------------------------
1 NULL A
2 NULL B
3 1 A1
4 1 A2
5 2 B1
It's a big table and can be very painful to look through. So I want to create a view that will display data in slightly better way:
Id ParentId ParentName Name Desc
--------------------------------------------
1 NULL A
3 1 A A1
4 1 A A2
2 NULL B
5 2 B B1
My problem is getting that ParentName into SELECT query. I obviously (tried) can't do:
SELECT Id, ParentId, (SELECT Name FROM myTable WHERE Id = ParentId) AS ParentName, Name, Desc FROM myTable INNER JOIN .. WHERE ... GROUP BY etc.
Do I have to resort to Common Table Expression (CTE) to get this done ?
Instead of using CTE, You can consider to do that by simple self-join concept:
Select T1.Id, T1.ParentId, ParentTable.Name as ParentName, T1.Name, T1.[Desc]
From tableName T1
Left join tableName ParentTable
on T1.ParentId = ParentTable.Id
order by Name
More reference on Self-Join from Microsoft's TechNet (ref pointer credited to destination-data)
Your example has one parent level only. If there might be deeper nestings you could use a recursive CTE. In this example I added two more elements as children below children:
DECLARE #tbl TABLE(Id INT,ParentId INT, Name VARCHAR(MAX));
INSERT INTO #tbl VALUES
(1,NULL,'A')
,(2,NULL,'B')
,(3,1,'A1')
,(4,1,'A2')
,(5,2,'B1')
,(6,4,'A2a')
,(7,6,'A2a1')
;
WITH RecursiveCTE AS
(
SELECT Id,ParentId,Name,Name AS FullPath
FROM #tbl AS tbl
WHERE ParentId IS NULL
UNION ALL
SELECT a.*
,derived.FullPath + '/' + a.Name
FROM RecursiveCTE AS derived
CROSS APPLY (SELECT Id,ParentId,Name FROM #tbl AS innerTbl WHERE innerTbl.ParentId=derived.Id) AS a
)
SELECT * FROM RecursiveCTE
The result
Id ParentId Name FullPath
1 NULL A A
2 NULL B B
5 2 B1 B/B1
3 1 A1 A/A1
4 1 A2 A/A2
6 4 A2a A/A2/A2a
7 6 A2a1 A/A2/A2a/A2a1