SQL Server select column while inserting - sql

This question is a part of an insert statement in which I am trying to select a value from another value that can be inserted into a column.
For example in my table OnlineServers, I have columns:
ID, ServerID, OnlineSince
In my second table ImportServers, I have columns with the data (The lines after NewYork and Paris are actually empty):
ImportServerName
NewYork
London
Paris
Tokyo
This question is related to SQL Server.
In my third table, which is a look-up table called ServerLookup, I have these columns with data:
ID, ServerName
0 Not specified
1 NewYork
2 London
3 Tokyo
4 Munich
5 Salzburg
Question: I want to have an sql statement which can select ID '0' from ServerLookup table if the value of the column ImportServerName is empty.
What I have so far is:
insert into OnlineServers (ServerID, OnlineSince)
select
(
select ID
from ServerLookup
where ServerLookup.ServerName = ImportServers.ServerName
or ServerLookup.ServerName = ''
),
GETDATE()
from ImportServers
The problem I am facing is if the server name is matched, it also returns an extra row with empty server name.
How can I fix this problem.
Thanks
PS: Forgive me if there is any typo in the code

INSERT INTO OnlineServers
SELECT CASE ImportServerName
WHEN '' THEN 0
ELSE ID
END AS ServerID, GetDate()
FROM ImportedServers s
LEFT JOIN ServerLookup l on s.ImportedServerName = l.ServerName;
This should do it. You LEFT JOIN so you get every record from ImportedServers and use CASE to get 0 where ImportServerName is blank.

Maybe something like this:
SELECT FIRST(column_name) FROM table_name;
Limiting the return to the first match, also, shoudl teh from not be inside the select brackets?
select FIRST(ID)
from ServerLookup
where ServerLookup.ServerName = ImportServers.ServerName
or ServerLookup.ServerName = ''
from ImportServers)

if i understand your problem correctly try something like this
insert into OnlineServers (ServerID, OnlineSince)
select TOP(1) ID ,GETDATE()
from ServerLookup
inner join ImportServers
on ServerLookup.ServerName = ImportServers.ServerName
Where ServerLookup.ServerName = ''

Related

Replacing multiple values of same block in SQL

I have column Conveyor with conveyor name entries in the table Report_Line which I want to replace with conveyor no.
Belt - 1 | Slack - 2 | Chain - 3
It's real time scenario, as soon as a row is added with data, according to the name of conveyor, it should get replaced with it's respective number.
I tried replace query with Union statement but didn't work, throws error
SELECT TOP 1 *
FROM Report_Line
ORDER BY Serial_no DESC
SELECT REPLACE(Conveyor, 'Slack', '2')
UNION
SELECT REPLACE(Conveyor, 'Belt', '1')
UNION
SELECT REPLACE(Conveyor, 'Chain', '3')
GO
You could try using an inline, hard-coded table, and join to it by the Conveyor names.
Something like this:
Select Top 1* FROM Report_Line
Left Join
(values ('Slack', '2'),('Belt', '1'),('Chain', '3')) sidetable(conveyor_name,id)
on sidetable.conveyor_name = Report_Line.Conveyor
Order by Serial_no DESC
GO

Calculate field with value based on select statement

I currently have a select statement which returns Customer Numbers that are primary.
What I would like to do for those returned, I would like to have another column that is for customerRole. For customerRole the value should be either primary or secondary.
My current select statement is bringing those that are primary and based on that select statement. I would like to have a customerRole column that shows these as primary. Then I would like to use this same column with my other select statement to show those that are secondary. When they are ran together I would like to see something like:
accountNumber: 1234455 CustomerRole: Primary
AccountNumber: 3245454 CustomerRole: Secondary
Does anyone know how I can accomplish this? Here is my select to get primary numbers:
SELECT
F.CustomerNumber
FROM ods.CustomerFact F
JOIN ods.holderDim AD
ON F.HolderRowNumber = AD.HolderRowNumber
JOIN ods.holderOwesDim B
ON F.PrimaryHolderNumber = B.SecondaryHolderNumber
I think you want a CASE expression:
SELECT c.CustomerNumber,
(CASE WHEN EXISTS (SELECT 1
FROM ods.holderDim hd
WHERE c.PrimaryHolderNumber = hd.SecondaryHolderNumber
) AND
EXISTS (SELECT 1
FROM ods.holderOwesDim hod
WHERE c.PrimaryHolderNumber = hod.SecondaryHolderNumber
THEN 'Primary' ELSE 'Secondary'
)
END) as role
FROM ods.CustomerFact c;

Stored procedure to count then divide a column

I don't exactly know how to title this question. But I am looking to create a stored procedure or procedures to create a new table with averages. I have 19 sites that I have collected survey data from. I want to count each column two but with two different conditions.
E.g.
SELECT COUNT(ColumnName)
FROM TableName
WHERE ColumnName = 3
SELECT COUNT(ColumnName)
FROM TableName
WHERE ColumnName = 4
From there I would like to add those two numbers together then divide by another count for another column in the table.
Basically I want to know how many surveys have the answer 3 and 4 then divide them by how many surveys were answered. Also keep in mind I want numbers based on each site.
Use group by:
select columnname
from tablename
where columnname in (3, 4)
group by columname;
You seems want :
select sum(case when col in (3,4) then 1 else 0 end) / count(*)
from table t
So I have gotten a bit closer to what I want trying to achieve but it is still not doing what I want it do. This is what I have come up with but I don't know how to get to divide by the sum. SELECT (SELECT COUNT() FROM Resident_Survey WHERE CanbealonewhenIwish = 3 and Village = 'WP' and Setting = 'LTC')+ (SELECT COUNT() FROM Resident_Survey WHERE CanbealonewhenIwish = 4 and Village = 'WP' and Setting = 'LTC')/ (SELECT COUNT(*) FROM Resident_Survey WHERE Village = 'WP' and Setting = 'LTC') AS ICanbealonewhenIwish
I figured it out. I was looking to create this query.
SELECT 100.0 *
COUNT(CASE WHEN Privacyisrespected IN (3,4)
THEN 1
ELSE NULL END) /
COUNT(*) AS Myprivacyisrespected
FROM Resident_Survey
WHERE Village = 'WP'
and Setting = 'LTC'

DB2 SQL Getting distinct value when grouping rows

BUSINESSTABLE looks like this:
HOTEL_CHAIN HOTEL_LOCATION HOTEL_OWNER
_____________________________________________________
Marriott Las Vegas Nelson
Best Western New York Richards
Best Western San Francisco Smith
Marriott New York Nelson
Hilton Boston James
I'm trying to execute an SQL statement in a DB2 database that groups these entries by HOTEL_CHAIN. If the rows that are grouped together contain the same HOTEL_LOCATION or HOTEL_OWNER, that info should be preserved. Otherwise, a value of 'NULL' should be displayed. For example, both Marriott hotels have the same owner, Nelson, so I want to display that information in the new table. However, each Marriott hotel is in a different location, so I'd like to display 'NULL' in that column.
The resulting table (HOTELTABLE) should look like this:
HOTEL_CHAIN HOTEL_LOCATION HOTEL_OWNER
_____________________________________________________
Marriott NULL Nelson
Best Western NULL NULL
Hilton Boston James
I'm trying to use the following SQL statement to accomplish this:
INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER)
SELECT
HOTEL_CHAIN,
CASE COUNT(DISTINCT(HOTEL_LOCATION)) WHEN 1 THEN HOTEL_LOCATION ELSE 'NULL' END,
CASE COUNT(DISTINCT(HOTEL_OWNER)) WHEN 1 THEN HOTEL_OWNER ELSE 'NULL' END,
FROM BUSINESSTABLE GROUP BY HOTEL_CHAIN
I get an SQL error SQLCODE-119 A COLUMN OR EXPRESSION IN A HAVING CLAUSE IS NOT VALID. It seems to be complaining about the 2nd HOTEL_LOCATION and the 2nd HOTEL_OWNER within my case statements. I also tried using DISTINCT(HOTEL_LOCATION) and that threw another error. Can someone please explain the correct way to code this? Thank you!
Don't use COUNT(DISTINCT). Use MIN() and MAX():
INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER)
SELECT HOTEL_CHAIN,
(CASE WHEN MIN(HOTEL_LOCATION) = MAX(HOTEL_LOCATION)
THEN MIN(HOTEL_LOCATION) ELSE 'NULL'
END),
(CASE WHEN MIN(HOTEL_OWNER) = MAX(HOTEL_OWNER)
THEN MIN(HOTEL_OWNER) ELSE 'NULL'
END)
FROM BUSINESSTABLE
GROUP BY HOTEL_CHAIN;
Notes:
Why not COUNT(DISTINCT)? It is generally much more expensive than MIN() and MAX() because it needs to maintain internal lists of all values.
I don't approve of a string value called 'NULL'. Seems like it is designed to foster confusion. Perhaps just NULL the value itself?
I agree Gordon for the null (gj Gordon).
other method
INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER)
select distinct f1.HOTEL_CHAIN,
case when f2.HasDiffLocation is not null then 'NULL' else f1.HOTEL_LOCATION end as HOTEL_LOCATION,
case when f3.HasDiffOwner is not null then 'NULL' else f1.HOTEL_OWNER end as HOTEL_OWNER
from BUSINESSTABLE f1
left outer join lateral
(
select 1 HasDiffLocation from BUSINESSTABLE f2b
where f1.HOTEL_CHAIN=f2b.HOTEL_CHAIN and f1.HOTEL_LOCATION<>f2b.HOTEL_LOCATION
fetch first rows only
) f2 on 1=1
left outer join lateral
(
select 1 HasDiffOwner from BUSINESSTABLE f3b
where f1.HOTEL_CHAIN=f3b.HOTEL_CHAIN and f1.HOTEL_OWNER<>f3b.HOTEL_OWNER
fetch first rows only
) f3 on 1=1
or like this :
INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER)
select distinct f1.HOTEL_CHAIN,
ifnull(f2.result, f1.HOTEL_LOCATION) as HOTEL_LOCATION,
ifnull(f3.result, f1.HOTEL_OWNER) as HOTEL_LOCATION,
from BUSINESSTABLE f1
left outer join lateral
(
select 'NULL' result from BUSINESSTABLE f2b
where f1.HOTEL_CHAIN=f2b.HOTEL_CHAIN and f1.HOTEL_LOCATION<>f2b.HOTEL_LOCATION
fetch first rows only
) f2 on 1=1
left outer join lateral
(
select 'NULL' result from BUSINESSTABLE f3b
where f1.HOTEL_CHAIN=f3b.HOTEL_CHAIN and f1.HOTEL_OWNER<>f3b.HOTEL_OWNER
fetch first rows only
) f3 on 1=1

How to use Order By clause on a column containing string values separated by comma?

I have a table with a column named Skills which contains comma separated values for different employees like
EmpID Skills
1 C,C++,Oracle
2 Java,JavaScript,PHP
3 C,C++,Oracle
4 JavaScript,C++,ASP
5 C,C++,JavaScript
So I want to write a query which will order all the employees first who knows JavaScript, how can I get this result?
You should not use one attribute to store multiple values. That goes against relation DB principles.
Instead of that you should create additional table to store skills and refer to employee in it. Then, your query will looks like:
SELECT
*
FROM
employees
LEFT JOIN employees_skills
ON employee.id=employees_skills.employee_id
WHERE
employees_skills='JavaScript'
Try this
SELECT *
FROM
(
SELECT *
,CASE WHEN Skills LIKE '%JavaScript%' THEN 0 ELSE 1 END AS Rnk
FROM MyTable
) T
ORDER BY rnk,EmpID
DEMO
OR
SELECT * FROM #MyTable
ORDER BY CASE WHEN Skills LIKE '%JavaScript%' THEN 0 ELSE 1 END,EmpID
select EmpID, Skills
from Table1
order by case when Skills like '%JavaScript%' then 0 else 1 end
Try this:
SELECT *
FROM YourTable
ORDER BY PATINDEX('%JavaScript%', Skills) DESC
But this is a bad way. You should really normalize your table.
For MySQL
select Skills from myTable
order by case Skills
when "Javascript" then 0
when "Java" then 1 when "C++" then 2
end
and so on
For SQL Server
select Skills from myTable
order by case
when Skills="Javascript" then 1
when Skill="Java" then 2
else 3
end
Make sure to start SQL server from 1 (That I'm not sure).
Include an else before end that will show all remaining results.
For more details about SQL Server see this or see this
This works for DB2/400:
with s (id, skill, rest) as
(select id, '', sk from skills
union all
select id, substr(rest, 1, locate(',',rest)-1),
substr(rest,locate(',',rest)+1)
from s
where locate(',',rest) > 0)
select id, skill from s
where skill = 'JavaScript'
order by id