Same value is shown only one, how make it? - sql

Hallo I need to show same column value only one,but each other column value show to next row.
For Example, I have tables Person(iD, name, surname) and Contact(iD, description, contact), and one person has tree contacts.
How can I make this report ?
iD Name Surname Description Contact
5 Johny Walker Email Johny.Walke#xzy.zz
Mobile 6546846168
Fax 688468

In theory something like the following construct should work in 8.1.6 or higher:
select
case r when 1 then p.id end as id,
case r when 1 then name end as name,
case r when 1 then surname end as surname,
description,
contact
from
person p, (
select
id,
row_number() over (partition by id) as r,
description,
contact
from
contact
) c
where p.id = c.id;
but you should add ordering to the window function and an order by to the results to force the output to always be in the correct order.

Related

sql join with condition

I've a table EMPLOYEE which has columns like these
EmpId FName LName
I have another table ADDRESS which has columns like these
EmpId AddressType Address Phone Email
AddressType column has 2 possible types, Residential and Official and an Emp can have both types of address. I need a query which will join these 2 tables using EmpId. It also needs to fetch one address which has phone not null. If both addresses has phone, then fetch any one, if none has phone, still fetch any one. Please help.
The trick is to first decide which Address would be best for the Employee, based on your Phone-rule. After the prefered Address has been found, indicated by PhonePreference = 1, you can JOIN the correct Address on the Employee.
WITH AddressCTE AS (
SELECT *
, ROW_NUMBER() OVER (
PARTITION BY EmpId
ORDER BY CASE WHEN Phone IS NOT NULL THEN 1 ELSE 2 END, Phone
) PhonePreference
FROM Address
)
SELECT *
FROM Employee E
JOIN AddressCTE A ON E.EmpId = A.EmpId AND A.PhonePreference = 1

Update fields in a SQL Server table sequentially

I have a table AoObject with a column DisplayName. In name are values like Joe Smith, John Smith, Jane Smith. This goes on for thousands of records.
I want to update the table so that starting with record one up to the last record the value of DisplayName is like this. Joe Smith = Customer1, John Smith = Customer2, Jane Smith = Customer3... and so on until all the name columns sequentially say Customer with a number appended to it and not the current value of the column.
This is SQL Server 2012
***The examples below don't work and I've amended my question. My fault for not including enough details. The table is called Aoobject. The field that needs to be changed is actually called DisplayName. I need to filter the result set with something like the following.
Where ObjectDescription in ('Portfolio Description', 'Portfolio Group Description')
This seems like a bad idea -- the "customer number" should be put into a separate column. It is not part of the name. However, it is easy to do:
with toupdate as (
select t.*, row_number() over (order by recordnum) as seqnum
from table t
)
update toupdate
set fullname = fullname + ' Customer' + cast(seqnum as varchar(255));
I am assuming that you have some numbering for the records (recordnum) because the question says "with record one up to the last record".
EDIT:
If you want the names to be unique, then append a number only for duplicate names.
with toupdate as (
select t.*,
row_number() over (partition by fullname order by recordnum) as fn_seqnum,
count(*) over (partition by fullname) as fn_cnt
from table t
)
update toupdate
set fullname = fullname + ':' + cast(fn_seqnum as varchar(255));
where fn_cnt > 1;
This appends a unique number only when it needs to (for fullnames that have duplicates). And, it keeps the cardinality of the number as low as possible, so only one digit should suffice for the suffix.
Something like this will do.
Hope the Customer name is unique.
;WITH cte_emp AS
(
SELECT CustomerName , ROW_NUMBER() over (order by CustomerName) slno
FROM Customer
)
UPDATE t SET CustomerName = 'Customer ' + cast(slno as varchar)
FROM Customer t
INNER JOIN cte_emp c ON t.CustomerName = c.CustomerName

Having problems identifying my mistake

The tables which are already created and unmodifiable are Book and Author.
Book (Title, Price, Yeareleased)
Author(AName,btitle,position)
Italized are the keys
and Btitle in Author is a foreign key that references Book(Title).
My SQL query:
select distinct AName
from Author
where position in (2,3) AND position<>1
group by AName
When I run this I get all the authors that have a book in position 2 or 3. Which is what I want but I'm only trying to get those authors which have a position 2 or 3 for all there books.
Essentially returning every author who was in the 2nd or 3rd position in all the books.
Maybe something like this would work:
select distinct AName
from #Author
where position in (2,3)
except
select distinct AName
from #Author
where position not in (2,3)
It makes a set of those authors who are in position 2 and 3 and then removes the ones who has another position.
It is not entirely clear whether someone who co-wrote 2 books and was listed second on one and third on the other should be selected or not. It is simpler to allow it; you can refine the query if you need the more stringent condition.
One way to answer this query makes the key observation that you're interested in authors for whom the count of the books they have written is equal to the count of the books where they are listed as second or third author.
Go for some TDQD — Test-Driven Query Design
Number of books each author wrote
SELECT Aname, COUNT(*) AS BookCount
FROM Author
GROUP BY AName
Number of books each author wrote as second or third author
SELECT Aname, COUNT(*) AS NonLeadAuthorCount
FROM Author
WHERE Position IN (2, 3)
GROUP BY Aname
Join those two where the counts are identical
SELECT X.Aname
FROM (SELECT Aname, COUNT(*) AS BookCount
FROM Author
GROUP BY AName
) AS X
JOIN (SELECT Aname, COUNT(*) AS NonLeadAuthorCount
FROM Author
WHERE Position IN (2, 3)
GROUP BY Aname
) AS Y
ON X.BookCount = Y.NonLeadAuthorCount
An alternative way of looking at is 'the set authors who have written a book in position 2 or 3 minus the set of authors who have written a book where the position is neither 2 nor 3'. For this, see the answer by jpw.
Trying to write standard SQL:
SELECT AName FROM (
SELECT
AName,
COUNT(*) AS count_all,
(SELECT COUNT(*) FROM Author AS aa WHERE aa.AName = a.AName AND position=2) AS count_2,
(SELECT COUNT(*) FROM Author AS aa WHERE aa.AName = a.AName AND position=3) AS count_3,
FROM Author AS a
GROUP BY AName
) AS t
WHERE count_all = count_2
OR count_all = count_3
I hope this work for you.
Try this:
select AName from Author where position=2 OR position=3 group by AName;
Try adding
and AName not in (select AName from Author where position != 2 and position != 3
Or something like that...

DB2 SQL Join and Max value

The database I'm accessing has two tables I need to query using DB2 SQL, shown here as nametable and addresstable. The query is for finding all of the people with a certain balance due. The addresses are stored in a separate table to keep track of address changes. In addresstable, the latest address is determined by a sequence number (ADDRSEQUENCE). The AddressID field is present in both tables, and is what ties each person to specific addresses. The highest sequence number is the current address. I need that current address for each person and only that one. I know I'm going to have to use MAX somewhere for the sequence number, but I can't figure out how to position it given the join. Here's my current query, which of course returns all addresses...
SELECT NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
NAMETABLE.NMELASTBUS AS LASTNAME,
NAMETABLE.NAME_FIRST AS FIRSTNAME,
NAMETABLE.BALDUE AS BALANCEDUE,
ADDRESSTABLE.STREETNAME AS ADDR,
ADDRESSTABLE.ADDRLINE2 AS
ADDRLINE2,ADDRESSTABLE.CITYPARISH AS CITY,
ADDRESSTABLE.ADDRSTATE AS STATE,
ADDRESSTABLE.ZIPCODE AS ZIP,
ADDRESSTABLE.ADDIDSEQNO AS ADDRSEQUENCE
FROM NAMETABLE JOIN ADDRESSTABLE ON NAMETABLE.ADDRESSID = ADDRESSTABLE.ADDRESSID
WHERE NAMETABLE.BALANCEDUE >= '50.00'
You can do a sub-select on the MAX(ADDRSEQUENCE) like so:
SELECT
N.ACCTNUM AS ACCOUNTNUMBER
,N.NMELASTBUS AS LASTNAME
,N.NAME_FIRST AS FIRSTNAME
,N.BALDUE AS BALANCEDUE
,A.STREETNAME AS ADDR,
,A.ADDRLINE2 AS
,A.ADDRLINE2
,A.CITYPARISH AS CITY,
,A.ADDRSTATE AS STATE,
,A.ZIPCODE AS ZIP,
FROM NAMETABLE AS N
JOIN ADDRESSTABLE AS A
ON N.ADDRESSID = A.ADDRESSID
WHERE N.BALANCEDUE >= '50.00'
AND A.ADDRSEQUENCE = (
SELECT MAX(ADDRSEQUENCE)
FROM ADDRESSTABLE AS A2
WHERE A.ADDRESSID = A2.ADDRESSID
)
This is pretty quick in DB2.
You can use a row_number and partition by to do this. Something like this:
with orderedaddress as (
select row_number() over (partition by ADDRESSID order by ADDRSEQUENCE desc) as rown,
STREETNAME,ADDRESSID, ... from ADDRESSTABLE
)
select NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
...
oa.STREETNAME
...
from NAMETABLE JOIN orderedaddress oa on NAMETABLE.ADDRESSID = oa.ADDRESSID
where oa.rown = 1
and NAMETABLE.BALANCEDUE >= '50.00'

Is it Possible to Use IF/Else in SQL?

Is it possible to use if/else in SQL? If I have a table called supplier with columns: sid -> primary key, sname and city.
Then I wish to:
select sid from supplier where city="taipei" if not empty.
Or select sid from supplier where city="tainan"
Yes, you can. I don't know about other DBMS but I have used such things in Microsot SQL Server in my Stored Procedure like this;
IF EXISTS
(SELECT [sid] FROM [supplier] WHERE [city]= "taipei")
select sid from supplier where city="taipei" // your true condition query
ELSE
select sid from supplier where city="tainan"
In MySQL From this link, it turns out that is also possible. see;
IF EXISTS(SELECT * FROM tbl_name WHERE category_code ='some-category-code') THEN UPDATE tbl_name SET active='0' WHERE category_code = 'some-category-code' END IF
It was unclear what you want to do (I leave my previous hypotheses below).
You want to associate a priority to your suppliers, so that the one for Taipei is selected, but if it is unavailable, then Tainan gets selected instead.
In this specific case you can just use:
SELECT sid FROM supplier WHERE city = (
SELECT MAX(city) FROM supplier WHERE city IN ('Taipei', 'Tainan')
);
The inner sub-SELECT will retrieve Taipei or, if unavailable, Tainan.
This uses the fact that Taipei is lexicographically greater than Tainan, but if you wanted a more flexible solution, MAX would not work. In that case you would change the subselect to sort cities in order of desirability (missing cities are of course undesirable) and then fetch the one most desirable:
SELECT sid FROM supplier WHERE city = (
SELECT city FROM supplier ORDER BY CASE
WHEN city = 'Taipei' THEN 1
WHEN city = 'Tainan' THEN 2
WHEN city = 'New York' THEN 3
ELSE 4
END
LIMIT 1
);
The subselect now will retrieve first Taipei, but missing Taipei it will get to Tainan and so on.
Note that if you want only one SID, you can do it much more simply:
SELECT sid FROM supplier ORDER BY CASE
WHEN city = 'Taipei' THEN 1
WHEN city = 'Tainan' THEN 2
WHEN city = 'New York' THEN 3
ELSE 4
END
LIMIT 1
This will retrieve all suppliers, but the one from Taipei, if available, will come out first; and the LIMIT 1 will truncate the response to that first row.
The solutions below do not apply
This will get sid from supplier where city is Taipei or Tainan (which of course means that city is not empty!):
SELECT sid FROM supplier WHERE city IN ('Taipei', 'Tainan');
This will get sid from supplier as above, provided sid is not empty:
SELECT sid FROM supplier WHERE city IN ('Taipei', 'Tainan') AND sid IS NOT NULL;
This will get sid from supplier as above, and replace sid if it is empty.
SELECT CASE WHEN sid IS NULL then 'Empty' ELSE sid END AS sid
FROM supplier WHERE city IN ('Taipei', 'Tainan');
Maybe you should provide two or three sample rows with the expected results.
Edit: sorry, I see now that sid is a primary key, which means it should never be empty. This means that cases 2 and 3 can never apply.
Then perhaps you mean that sname is not empty?:
SELECT sid FROM supplier WHERE city IN ('Taipei', 'Tainan')
AND sname IS NOT NULL AND sname != '';
The following selects a supplier if there is one in taipei, otherwise it selects the one in Tainan. If none of them exists, nothing will be returned.
select sid
from supplier
where city = 'Taipei'
union all
select sid
from supplier
where city = 'Tainan'
and not exists (select 1 from supplier where city = 'taipei')