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

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

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)

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

Crosstab/Pivot query in TSQL on nvarchar columns

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

Counting values in columns

What I am looking for is to group by and count the total of different data in the same table and have them show in two different columns. Like below.
Data in table A
Fields:
Name Type
Bob 1
John 2
Bob 1
Steve 1
John 1
Bob 2
Desired result from query:
Name Type 1 Type 2
Bob 2 1
John 1 1
Steve 1 0
This will do the trick in SQL Server:
SELECT
name,
SUM( CASE type WHEN 1 THEN 1 ELSE 0 END) AS type1,
SUM( CASE type WHEN 2 THEN 1 ELSE 0 END) AS type2
FROM
myTable
GROUP BY
name
No time to write the code, but the Case statement is what you want here. SImply havea value of 1 if it meets the case and zero if it deosn't. Then you can sum the columns.
Use two separate GROUP BY subqueries.
SELECT Name, a.Count1, b.Count2
from myTable
JOIN
(SELECT Name, SUM(Type) AS Count1 FROM myTable GROUP BY Name WHERE Type=1) AS a ON a.Name = myTable.Name
(SELECT Name, SUM(Type) FROM myTable GROUP BY Name WHERE Type=2) AS b ON b.Name = myTable.Name
You're looking for a CrossTab solution. The above solutions will work, but you'll come unstuck if you want a general solution and have N types.
A CrossTab solution will solve this for you. If this is for quickly crunching some numbers then dump your data into Excel and use the native Pivot Table feature.
If it's for a RDBMS in an app, then it depends upon the RDBMS. MS SQL 2005 and above has a crosstab syntax. See:
http://www.databasejournal.com/features/mssql/article.php/3521101/Cross-Tab-reports-in-SQL-Server-2005.htm
#Seb has a good solution, but it's server-dependent. Here's an alternate using subselects that should be portable:
select
name,
(select count(type) from myTable where type=1 and name=a.name) as type1,
(select count(type) from myTable where type=2 and name=a.name) as type2
from
myTable as a
group by
name

Select values in SQL that do not have other corresponding values except those that i search for

I have a table in my database:
Name | Element
1 2
1 3
4 2
4 3
4 5
I need to make a query that for a number of arguments will select the value of Name that has on the right side these and only these values.
E.g.:
arguments are 2 and 3, the query should return only 1 and not 4 (because 4 also has 5). For arguments 2,3,5 it should return 4.
My query looks like this:
SELECT name FROM aggregations WHERE (element=2 and name in (select name from aggregations where element=3))
What do i have to add to this query to make it not return 4?
A simple way to do it:
SELECT name
FROM aggregations
WHERE element IN (2,3)
GROUP BY name
HAVING COUNT(element) = 2
If you want to add more, you'll need to change both the IN (2,3) part and the HAVING part:
SELECT name
FROM aggregations
WHERE element IN (2,3,5)
GROUP BY name
HAVING COUNT(element) = 3
A more robust way would be to check for everything that isn't not in your set:
SELECT name
FROM aggregations
WHERE NOT EXISTS (
SELECT DISTINCT a.element
FROM aggregations a
WHERE a.element NOT IN (2,3,5)
AND a.name = aggregations.name
)
GROUP BY name
HAVING COUNT(element) = 3
It's not very efficient, though.
Create a temporary table, fill it with your values and query like this:
SELECT name
FROM (
SELECT DISTINCT name
FROM aggregations
) n
WHERE NOT EXISTS
(
SELECT 1
FROM (
SELECT element
FROM aggregations aii
WHERE aii.name = n.name
) ai
FULL OUTER JOIN
temptable tt
ON tt.element = ai.element
WHERE ai.element IS NULL OR tt.element IS NULL
)
This is more efficient than using COUNT(*), since it will stop checking a name as soon as it finds the first row that doesn't have a match (either in aggregations or in temptable)
This isn't tested, but usually I would do this with a query in my where clause for a small amount of data. Note that this is not efficient for large record counts.
SELECT ag1.Name FROM aggregations ag1
WHERE ag1.Element IN (2,3)
AND 0 = (select COUNT(ag2.Name)
FROM aggregatsions ag2
WHERE ag1.Name = ag2.Name
AND ag2.Element NOT IN (2,3)
)
GROUP BY ag1.name;
This says "Give me all of the names that have the elements I want, but have no records with elements I don't want"