Crosstab/Pivot query in TSQL on nvarchar columns - sql

I have a Table1:
ID Property
1 Name
2 City
3 Designation
and Table2:
ID RecordID Table1ID Value
1 1 1 David
2 1 2 Tokyo
3 2 1 Scott
4 2 3 Manager
The Table1ID of Table2 maps to Table1's ID. Now I wish to show the Table1 Property column values as column headers and have a result set in format like:
RecordID Name City Designation
1 David Tokyo NULL
2 Scott NULL Manager
What is the best/efficient way to achieve this in T-SQL considering that the number of records in Table1 (i.e. the columns in result set) can change and thus should be handled dynamically.
Although I tried PIVOT and CASE based queries, but have been struggling with both of them. :(
Any help/guidance would be appreciated.
Thanks!
Update:
I've been able to create the dynamic query, but one thing which I am still not able to understand is why MAX has been used in the CASE statements. Kindly ignore my noobness.

Use:
SELECT t2.recordid,
MAX(CASE WHEN t1.property = 'Name' THEN t2.value END) AS name,
MAX(CASE WHEN t1.property = 'City' THEN t2.value END) AS city,
MAX(CASE WHEN t1.property = 'Designation' THEN t2.value END) AS designation
FROM TABLE2 t2
JOIN TABLE1 t1 ON t1.id = t2.table1id
GROUP BY t2.recordid
ORDER BY t2.recordid

Related

SQL UPDATE on the same table with WHERE

I have the following table and I want to fill up the empty values of the name column with the same value of the name where id_lang=2.
Any idea of what the sql query should be?
id_product
id_lang
name
1
1
-
1
2
name1
2
1
-
2
2
name2
3
1
-
3
2
name3
4
1
-
4
2
name4
One general approach which should work uses a correlated subquery:
UPDATE yourTable t1
SET name = (SELECT name FROM yourTable t2
WHERE t2.id_product = t1.id_product AND t2.id_lang = 2)
WHERE
name IS NULL;
In a query, you can simply use window function:
select t.*,
coalesce(name,
max(case when id_lang = 2 then name end) over (partition by id_product)
) as imputed_name
from t;
Note: This assumes that - really means NULL. If it is a string, the above can be tweaked to use CASE.
You can easily do this in an update as well, if you want to change the data in the table. However, the best way to do that depends on the database.
You can use a subquery: UPDATE table SET name = (SELECT DISTINCT name FROM table WHERE id_lang = 2)

how to name two columns dependind on another column value for a table in SQL server

I need to name two columns for a table in SQL server.
table1:
id type value
1 th 81648
1 nh 9794
2 nh 7689
2 th 9895
I need to get a table:
id value_th value_nh // the column names depend on type
1 81648 9794
2 9895 7689
How to design the SQL query?
You can do this with pivot. I prefer conditional aggregation:
select t.id,
max(case when type = 'nh' then value end) as value_nh,
max(case when type = 'th' then value end) as value_th
from table t
group by t.id
just use a simple join with nested selects:
select t1.id,t1.value_nh ,t2.value_th from
(select id, value as value_nh where type='nh') t1
join (select id, value as value_th where type='th') t2 on t1.id=t2.id

How to select id's that have rows for all values from a set

I want to select all Id from a table that have rows for both programs 'basketball' and 'football'
Given a table like this:
Id program
1 basketball
2 football
3 basketball
2 basketball
1 football
4 football
5 basketball
How can I get a result like this:
id
1
2
Since you want to return the id's that have both values football and basketball, you can use the following to get the result:
select id
from yt
where program in ('basketball', 'football')
group by id
having count(distinct program) = 2;
See SQL Fiddle with Demo.
Since can also be done by joining on your table multiple times:
select t1.id
from yt t1
inner join yt t2
on t1.id = t2.id
where t1.program = 'basketball'
and t2.program = 'football';
See SQL Fiddle with Demo
I think aggregation is the most generalizable approach for this:
select id
from table
group by id
having sum(case when program = 'Football' then 1 else 0 end) > 0 and
sum(case when program = 'Basketball' then 1 else 0 end) > 0
The sum() statement are counting the number of rows that have "football" and "basketball" respectively. When present, the number is greater than 0.
You can do this with IN or OR syntax:
SELECT id
FROM table
WHERE program = 'basketball'
OR program = 'football';
If you want to only get the first two results, add LIMIT 2 to the end.
By the way, it's really bad practice to have a table without a primary key, there is no way to index this table so performance would be very bad.

Oracle/SQL Couting multiple colums grouped by a common column

I'm back with yet another Oracle query. What I want to do is do counting on multiple columns grouped by a common field. I have half of this done so far. So given the following table
THING ACTION
--------------
T1 _A_
T1 _A_
T1 _B_
T2 _A_
T2 _B_
I have this query
select THING,
count(ACTION) as "A"
from <table>
where ACTION = '_A_'
group by THING
Which results in
THING A
----------
T1 2
T2 1
What I would like to see though is this
THING A B
--------------
T1 2 1
T2 1 1
But I'm not certain how to do that. Any ideas?
Thanks!
select thing,
count(case action when '_A_' then 1 end) as a,
count(case action when '_B_' then 1 end) as b
from <table>
group by thing
or sum(case action when '_A_' then 1 else 0 end) if you prefer

Add Column values in sql server query

I have result of two queries like:
Result of query 1
ID Value
1 4
2 0
3 6
4 9
Result of query 2
ID Value
1 6
2 4
3 0
4 1
I want to add values column "Value" and show final result:
Result of Both queries
ID Value
1 10
2 4
3 6
4 10
plz guide me...
select id, sum(value) as value
from (
select id, value from query1
uninon all
select id, value from query2
) x
group by id
Try using a JOIN:
SELECT
T1.ID,
T1.Value + T2.Value AS Value
FROM (...query1...) AS T1
JOIN (...query2...) AS T2
ON T1.Id = T2.Id
You may also need to consider what should happen if there is an Id present in one result but not in the other. The current query will omit it from the results. You may want to investigate OUTER JOIN as an alternative.
A not particularly nice but fairly easy to comprehend way would be:
SELECT ID,SUM(Value) FROM
(
(SELECT IDColumn AS ID,ValueColumn AS Value FROM TableA) t1
OUTER JOIN
(SELECT IDColumn AS ID,ValueColumn AS Value FROM TableB) t2
) a GROUP BY a.ID
It has the benefits of
a) I don't know your actual table structure so you should be able to work out how to get the two 'SELECT's working from your original queries
b) If ID doesn't appear in either table, that's fine