How to show the result as vertical in SQL
i have an idea using PIVOT but i can't make it to work.
SELECT '1' ID
, 'Vincent' Name
, 'Enteng' NickName
, 'Male' Gender
Result is:
but i want the result to be
ID 1
Name Vincent
NickName Enteng
Gender Male
If you are just dealing with one record, then use union all:
SELECT 'ID' as which, '1' as value union all
SELECT 'Name', 'Vincent' union all
SELECT 'NickName', 'Enteng' union all
SELECT 'Gender', 'Male'
Note in some databases, you might need from dual or even another construct.
Related
Say that I have the following table:
with data as (
select 'John' "name", 'A' "tag", 10 "count"
union all select 'John', 'B', 20
union all select 'Jane', 'A', 30
union all select 'Judith', 'A', 40
union all select 'Judith', 'B', 50
union all select 'Judith', 'C', 60
union all select 'Jason', 'D', 70
)
I know there are a number of distinct tag values, namely (A, B, C, D).
I would like to select the unique names that only have the tag A
I can get close by doing
-- wrong!
select
distinct("name")
from data
group by "name"
having count(distinct tag) = 1
however, this will include unique names that only have 1 distinct tag, regardless of what tag is it.
I am using PostgreSQL, although having more generic solutions would be great.
You're almost there - you already have groups with one tag, now just test if it is the tag you want:
select
distinct("name")
from data
group by "name"
having count(distinct tag) = 1 and max(tag)='A'
(Note max could be min as well - SQL just doesn't have single() aggregate function but that's different story.)
You can use not exists here:
select distinct "name"
from data d
where "tag" = 'A'
and not exists (
select * from data d2
where d2."name" = d."name" and d2."tag" != d."tag"
);
This is one possible way of solving it:
select
distinct("name")
from data
where "name" not in (
-- create list of names we want to exclude
select distinct name from data where "tag" != 'A'
)
But I don't know if it's the best or most efficient one.
I am begginer to sql , need a help, how can i segregate the marks of a student only when the pass flag is Y . currently for learning purpose , i have created a table and added 3 columns with two Y flag and one N flag. The query should only return sum of mark only when all the flag is Y.
Can someone help .
Thanks,
You can use a HAVING clause and conditional aggregation:
SELECT name,
SUM(marks)
FROM table_name
GROUP BY name
HAVING COUNT(CASE WHEN pass = 'N' THEN 1 END) = 0
Which, for the sample data:
CREATE TABLE table_name (
name VARCHAR(10),
marks NUMERIC,
pass VARCHAR(1)
);
INSERT INTO table_name (name, marks, pass)
SELECT 'xxx', 50, 'Y' UNION ALL
SELECT 'xxx', 50, 'Y' UNION ALL
SELECT 'zzz', 50, 'N';
Outputs the "sum of mark only when all the flag is Y.":
name
SUM(marks)
xxx
100
db<>fiddle here
I want to exclude people who have joined a specific group. For example, if some students signed up for an Orchestra club, and I want to retrieve a list of students who did NOT sign up for orchestra, how do I do so?
I am unable to simply do a Group By clause because some students may have joined multiple clubs, and would bypass the Where condition and still show up in the query,
as shown here.
I am thinking about using a CASE statement in the SELECT clause to flag the person as '1' if they have joined Orchestra, and '0' if they have not, but I'm struggling to write an aggregate CASE function, which would cause issues from the GROUP BY clause.
Any thoughts on how to flag people with a certain row value?
Apparently my table didn't get saved onto SQLFiddle so you can paste the code below on your own screen:
CREATE TABLE activity ( PersonId, Club) as
select 1, 'Soccer' from dual union
select 1, 'Orchestra' from dual union
select 2, 'Soccer' from dual union
select 2, 'Chess' from dual union
select 2, 'Bball' from dual union
select 3, 'Orchestra' from dual union
select 3, 'Chess' from dual union
select 3, 'Bball' from dual union
select 4, 'Soccer' from dual union
select 4, 'Bball' from dual union
select 4, 'Chess' from dual;
Use the HAVING clause instead of using WHERE, with case expression :
HAVING max(case when column = ‘string’ then 1 else 0 end) = 0
Add this after your group by .
How about selecting a list of user ids from the activity table and excluding it:
SELECT * FROM users WHERE id NOT IN
(SELECT PersonId FROM activity WHERE Club = 'Orchestra');
You could use a subquery to return a list of people to exclude.
-- Returns person 2 and 4.
SELECT
PersonId
FROM
activity
WHERE
PersonId NOT IN
(
-- People to exclude.
SELECT
PersonId
FROM
activity
WHERE
Club = 'Orchestra'
)
GROUP BY
PersonId
;
EDIT Removed superfluous distinct in subquery - thanks #mathguy.
select * from
(
select a.*, case when Club ='Orchestra' then 1 else 0 end flag
from activity a
) where flag =1; --> get some students signed up for an Orchestra club
select * from
(
select a.*, case when Club ='Orchestra' then 1 else 0 end flag
from activity a
) where flag =0; --> get students not signed up for an Orchestra club
I'm working on a query to get student contact mailing addresses, and am at point where I am a bit stuck. I have managed to get a list of all student, and their contacts, but now when i try and join the contacts to their addresses, i'm not exactly sure how to get the correct address.
In the address table can hold multiple kinds of addresses (Home, Mailing, Business, Pickup, Dropoff) and basically what i need to do is only bring back one address per contact.
Normally this would be the home address, unless there is a mailing address
So my question is how do i write some type of conditional statement to only get entries WHERE ADDRESS_TYPE_NAME = 'Home' unless there is also an entry WHERE ADDRESS_TYPE_NAME = 'Mailing' for the same PERSON_ID?
Thanks
with CTE as
(
select Person_id,
Address_Type_Name,
Address_Info -- replace with your real column names
from Address_Table
where Address_Type_Name in ('Home','Mailing')
)
select Person_id, Address_info
from CTE a1
where Address_Type_Name = 'Home'
and not exists (select 1
from CTE a2
where a2.Address_Type_Name = 'Mailing'
and a2.Person_id = a1.Person_id)
union
select Person_id, Address_info
from CTE a1
where Address_Type_Name = 'Mailing'
You can prioritize Address Type and get highest priority type with
select Person_id,
case min(case Address_Type_Name
when 'Mailing' then 1
when 'Home' then 2
-- more
end)
when 1 then 'Mailing'
when 2 then 'Home'
-- more
end Best_Address_Type_Name
from Address_Table
group by Person_id;
Then join the result to your data as needed
Here is one way to do it, using the row_number() analytic function and not requiring any joins, explicit or implicit. It also handles various special cases: a student who has neither mailing nor home address (but still needs to be shown in the output), and another student with two mailing addresses (in which case a random one is chosen; if there are criteria to prefer one to the other, the query can be easily adapted to accommodate that).
with
students ( id, name, address_type, address ) as (
select 11, 'Andy', 'home' , '123 X street' from dual union all
select 11, 'Andy', 'office' , 'somewhere else' from dual union all
select 15, 'Eva' , 'mailing', 'post office' from dual union all
select 18, 'Jim' , 'office' , '1 building' from dual union all
select 30, 'Mary', 'mailing', 'mail addr 1' from dual union all
select 30, 'Mary', 'office' , '1 building' from dual union all
select 30, 'Mary', 'home' , 'her home' from dual union all
select 30, 'Mary', 'mailing', 'mail addr 2' from dual
)
-- End of test data (not needed for the SQL query - reference your actual table)
select id, name, address_type,
case when address_type is not null then address end as address
from (
select id, name,
case when address_type in ('home', 'mailing')
then address_type end as address_type,
address,
row_number() over (partition by id
order by case address_type when 'mailing' then 0
when 'home' then 1 end) as rn
from students
)
where rn = 1
;
ID NAME ADDRESS_TYPE ADDRESS
--- ---- ------------ --------------
11 Andy home 123 X street
15 Eva mailing post office
18 Jim
30 Mary mailing mail addr 1
4 rows selected.
I have 5 random names each for male and female. I need to insert random names based on the gender. But how can we insert names in random from a set of 5 names in SQL. Is it possible?
select name from table order by newid()
Create a table with the names, and an integer ID. Then use RAND() with % 5 to get down to a value between 0 and 4 inclusively. Add 1 if you want a male, and 6 if you want a female. Like so:
Create table RandomNames
(id int,
name varchar(100),
gender char(1)
)
insert into RandomNames
(id, name,gender)
select 1,'Bill','M'
union
select 2,'John','M'
union
select 3,'Steve','M'
union
select 4,'Mike','M'
union
select 5,'Phil','M'
union
select 6,'Sarah','F'
union
select 7,'Ann','F'
union
select 8,'Marie','F'
union
select 9,'Liz','F'
union
select 10,'Stephanie','F'
declare #wantedGender char(1)
select #wantedGender = 'M'
select name
from RandomNames
where id = (CAST(RAND()*100 as int) % 5) + case when #wantedGender = 'M' then 1 else 6 end
Store the 5 random names for male in one table and the 5 random names for female in another table. Select a random integer between 1 and 5 and cross reference to male or female table using an inner join.
Create a function
CREATE FUNCTION [dbo].[getRandomName](#gen varchar(10))
RETURNS #name varchar(50)
AS
BEGIN
SELECT TOP 1 #name = name FROM table WHERE gender=#gen ORDER BY newid()
END
Then, just pass #gen to the function like this
select dbo.getRandomName('male')
Or, update many rows like this:
UPDATE myNewTable
SET newName=dbo.getRandomName('male')
WHERE gender='male'
In SQL Server, the best way to get "random" is to use newid(). You can sort by this to get a sorted list.
If you have five names for each gender, you can use a CTE to store them. The insert would then look like:
with names as (
select 'M' as gender, 'Alexander' as name union all
select 'M', 'Burt' union all
select 'M', 'Christopher' union all
select 'M', 'Daniel' union all
select 'M', 'Eric' union all
select 'F', 'Alexandra' union all
select 'F', 'Bertha' union all
select 'F', 'Christine' union all
select 'F', 'Daniela' union all
select 'F', 'Erica'
)
insert into table(name)
select top 1 name
from names
where gender = #MyGender
order by newid();
select top 1 name from RandomNames
where gender = 'M' order by newid()
Sample fiddle