How to make select with extra columns that depends on existing ones - sql

There goes example:
select * from table
and got
ID | NAME | MAIL | BOSS_ID |
1 | Mike | mike#mike.com | 2 |
2 | Josh | josh#hotmail.com | null |
What I actually want to do is make SELECT statement (somehow?) to show two more columns like:
ID | NAME | MAIL | BOSS_ID | BOSS_NAME | BOSS_MAIL
1 | Mike | mike#dfsfs.com | 2 | Josh | josh#dsa.com
2 | Josh | josh#dfsa.com | null | null | null
I know it looks silly, but that what I exactly have been asked to do...
All hints are much appreciatted!

You do an outer join to the table itself on ID and BOSS_ID.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table YourTable
(
ID int,
Name varchar(10),
Mail varchar(20),
BOSS_ID int
)
insert into YourTable values
(1 , 'Mike' , 'mike#mike.com' , 2),
(2 , 'Josh' , 'josh#hotmail.com' , null)
Query 1:
select T1.ID,
T1.Name,
T1.Mail,
T2.Name as BossName,
T2.Mail as BossMail
from YourTable as T1
left outer join YourTable as T2
on T1.BOSS_ID = T2.ID
Results:
| ID | NAME | MAIL | BOSSNAME | BOSSMAIL |
|----|------|------------------|----------|------------------|
| 1 | Mike | mike#mike.com | Josh | josh#hotmail.com |
| 2 | Josh | josh#hotmail.com | (null) | (null) |

You cannot SELECT columns that do not exist. You will need to add them. You would want an ALTER TABLE statement like this:
ALTER TABLE yourtable ADD BOSS_NAME VARCHAR( 255 )

Related

Multiple queries resulting in minimum number of occurrences

I need to find the smallest number of documents retrieved by any subject based on exp_condition. Exp_condition from the subjects table contains a '1' and a '2' column.
Here are the tables:
subjects table:
+-----------------+--------------+
| Field | Type |
+-----------------+--------------+
| username | varchar(255) |
| user_type | varchar(10) |
| years | int |
| low_grade | int |
| high_grade | int |
| on_line | varchar(10) |
| on_line_sources | varchar(255) |
| location | varchar(5) |
| exp_condition | int |
+-----------------+--------------+
tasks table:
+------------+--------------+
| Field | Type |
+------------+--------------+
| username | varchar(255) |
| task | varchar(5) |
| confidence | int |
| sim_helpd | int |
+------------+--------------+
docs table:
+--------------+--------------+
| Field | Type |
+--------------+--------------+
| username | varchar(255) |
| task | varchar(5) |
| doc_type | varchar(10) |
| used_tool | int |
| relevant | int |
| motivational | int |
| concepts | int |
| background | int |
| grade_level | int |
| hands_on | int |
| attachments | int |
+--------------+--------------+
I'm able to generate the number of subjects and number of documents for both exp_condition values. I'm allowed to use multiple queries, but I'm not sure how.
Code for generating number of subjects for exp_condition 1 and 2:
select count(distinct(t2.username))
from tasks as t1
inner join subjects as t2
on t1.username = t2.username group by exp_condition;
Code for generating number of documents for exp_condition 1 and 2:
select count(*), exp_condition
from docs as t1
left join subjects as t2
on t1.username = t2.username
group by exp_condition;
Expected output: two separate numbers for smallest number of documents retrieved by any subject based on exp_condition.
Thanks in advance.
You can use a subquery or a CTE
SubQuery
SELECT exp_condition, MIN(A) as Tasks, MIN(B) as Docs FROM (
SELECT exp_condition, COUNT(DISTINCT t2.username) A, COUNT(DISTINCT (t3.username) B
FROM subjects s
LEFT JOIN tasks T2 ON s.username = t2.username
LEFT JOIN docs T3 ON s.username = t3.username
GROUP BY exp_condition
) A
GROUP BY ex_condition
CTE
;WITH CTE AS (
SELECT exp_condition, COUNT(DISTINCT t2.username) A, COUNT(DISTINCT (t3.username) B
FROM subjects s
LEFT JOIN tasks T2 ON s.username = t2.username
LEFT JOIN docs T3 ON s.username = t3.username
GROUP BY exp_condition
)
SELECT exp_condition, MIN(A) as Tasks, MIN(B) as Docs
FROM CTE
GROUP BY ex_condition

Getting the last updated name

I am having a table having records like this:
+------+------+
| ID | name |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | A |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
+------+------+
I need to get value of A after it was last updated from a different value, for example here it would be the row at ID 6.
Try this query (MySQL syntax):
select min(ID)
from records
where name = 'A'
and ID >=
(
select max(ID)
from records
where name <> 'A'
);
Illustration:
select * from records;
+------+------+
| ID | name |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | A |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
+------+------+
-- run query:
+---------+
| min(ID) |
+---------+
| 6 |
+---------+
Using the Lag function...
SELECT Max([ID])
FROM (SELECT [name], [ID],
Lag([name]) OVER (ORDER BY [ID]) AS PrvVal
FROM tablename) tbl
WHERE [name] = 'A'
AND prvval <> 'A'
Online Demo: http://www.sqlfiddle.com/#!18/a55eb/2/0
If you want to get the whole row, you can do this...
SELECT Top 1 *
FROM (SELECT [name], [ID],
Lag([name]) OVER (ORDER BY [ID]) AS PrvVal
FROM tablename) tbl
WHERE [name] = 'A' AND prvval <> 'A'
ORDER BY [ID] DESC
Online Demo: http://www.sqlfiddle.com/#!18/a55eb/22/0
The ANSI SQL below uses a self-join on the previous id.
And the where-clause gets those with a name that's different from the previous.
select max(t1.ID) as ID
from YourTable as t1
left join YourTable as t2 on t1.ID = t2.ID+1
where (t1.name <> t2.name or t2.name is null)
and t1.name = 'A';
It should work on most RDBMS, including MS Sql Server.
Note that with the ID+1 that there's an assumption that are no gaps between the ID's.

SQL querying two sources

I have a View and Table as example below
Table1
+---------+------+
| Country | City |
+---------+------+
| UK | LDN |
| US | NEY |
| US | LAX |
+---------+------+
View1
+---------+---------+-------+
| Column1 | Column2 | Site |
+---------+---------+-------+
| Test | Test2 | UKLDN |
| Test | Test2 | USNEY |
| Test | Test2 | USLAX |
| Test | Test2 | PELMA |
+---------+---------+-------+
The result i'm trying to achieve is show all rows from View1, that have a View1.Site column matching Table1.Country and Table1.City. My confusion is how do to it as i'm not an sql person but more C# etc.
The resulting data I want to create is below. I don't know if I can do this solely from View1 or what functions to use.
Result
+---------+---------+-------+---------------+
| Column1 | Column2 | Site | ExistInTable1 |
+---------+---------+-------+---------------+
| Test | Test2 | UKLDN | Y |
| Test | Test2 | USNEY | Y |
| Test | Test2 | USLAX | Y |
| Test | Test2 | PELMA | N |
+---------+---------+-------+---------------+
Thanks
You can try this.
SELECT V.*, CASE WHEN T.Country IS NULL THEN 'N' ELSE 'Y' END ExistInTable1 FROM View1 V
LEFT JOIN Table1 T ON V.Site = (T.Country + T.City)
This is T-SQL, but the format should be very similar for most other flavors of SQL.
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Table1 (Country varchar(5),City varchar(5)) ;
INSERT INTO Table1 (Country,City)
VALUES ( 'UK','LDN'),('US','NEY'),('US','LAX')
;
CREATE TABLE View1 (Column1 varchar(10), Column2 varchar(10), Site varchar(10)) ;
INSERT INTO View1 (Column1,Column2,Site)
VALUES ('Test','Test2','UKLDN')
, ('Test','Test2','USNEY')
, ('Test','Test2','USLAX')
, ('Test','Test2','PELMA')
;
Query 1:
SELECT v.Column1, v.Column2
, CASE WHEN LEN(COALESCE(t.Country,t.City)) > 0 THEN 'Y' ELSE 'N' END AS ExistsInTable1
FROM View1 v
LEFT OUTER JOIN Table1 t ON v.Site = (t.Country+t.City)
Results:
| Column1 | Column2 | ExistsInTable1 |
|---------|---------|----------------|
| Test | Test2 | Y |
| Test | Test2 | Y |
| Test | Test2 | Y |
| Test | Test2 | N |
You need to do a LEFT JOIN with your table and then check if it matches or not with the info from the view, like this:
SELECT
VW.Column1
,VW.Column2
,VW.Site
,CASE WHEN ISNULL(T.country, T.city) IS NULL THEN 'N' ELSE 'Y' END AS ExistInTable1
FROM View1 VW
LEFT JOIN Table1 T
ON VW.site = CONCAT(T.country, T.City)
The LEFT JOIN keyword returns all records from the left table (View1), and the matched records from the right table (Table1). The result is NULL from the right side, if there is no match.(check done with the CASE statement)
You can test it Here as well.

Showing only duplicate rows from table in postgres

I have table like this:
--------------------------------------
| id | name | phone_number | address |
--------------------------------------
| 1 | Ram | 9090909090 | Delhi |
| 2 | Shyam| 9865444456 | Mumbai |
| 3 | Mohan| 9756543455 | Chennai |
| 4 | Ram | 9090909090 | Delhi |
--------------------------------------
I want to return the rows having same column data. The result will be like this:
--------------------------------------
| id | name | phone_number | address |
--------------------------------------
| 1 | Ram | 9090909090 | Delhi |
| 4 | Ram | 9090909090 | Delhi |
--------------------------------------
This can be done using window functions which avoids the join on the aggregated data and is usually the faster way:
select *
from (
select id,name,phone_number,address
count(*) over (partition by name,phone_number,address) as cnt
from the_table
) t
where cnt > 1;
SELECT t2.id,t2.name,t2.phone_number,t2.address
FROM
(
SELECT name,phone_number,address
FROM tableName
GROUP BY name,phone_number,address
HAVING COUNT(*) > 1
) AS t1
INNER JOIN tableName t2
ON t1.name=t2.name AND t1.phone_number=t2.phone_number AND t1.address=t2.address
Please run the below query, (consider table name to be "data"), to get the desired result as follows:
SELECT * FROM data where name IN (SELECT name FROM data GROUP BY name HAVING COUNT(*) > 1);
SELECT T1.*
FROM
table_name T1
INNER JOIN table_name T2 ON
T1.name= T2.nam` AND
T1.phone_number= T2.phone_number AND T1.address= T2.address
WHERE T2.id <> T1.id

Find and update specific duplicates in MS SQL

given below table:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | NULL |
| 2 | Ashly | Baboon | 09898788909 | NULL |
| 3 | James | Vangohg | 04333989878 | NULL |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
I want to use MS SQL to find and update duplicate (based on name, last name and number) but only the earlier one(s). So desired result for above table is:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | DUPE |
| 2 | Ashly | Baboon | 09898788909 | DUPE |
| 3 | James | Vangohg | 04333989878 | DUPE |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
This query uses a CTE to apply a row number, where any number > 1 is a dupe of the row with the highest ID.
;WITH x AS
(
SELECT ID,NAME,[LAST NAME],PHONE,STATE,
ROW_NUMBER() OVER (PARTITION BY NAME,[LAST NAME],PHONE ORDER BY ID DESC)
FROM dbo.YourTable
)
UPDATE x SET STATE = CASE rn WHEN 1 THEN NULL ELSE 'DUPE' END;
Of course, I see no reason to actually update the table with this information; every time the table is touched, this data is stale and the query must be re-applied. Since you can derive this information at run-time, this should be part of a query, not constantly updated in the table. IMHO.
Try this statement.
LAST UPDATE:
update t1
set
t1.STATE = 'DUPE'
from
TableName t1
join
(
select name, last_name, phone, max(id) as id, count(id) as cnt
from
TableName
group by name, last_name, phone
having count(id) > 1
) t2 on ( t1.name = t2.name and t1.last_name = t2.last_name and t1.phone = t2.phone and t1.id < t2.id)
If my understanding of your requirements is correct, you want to update all of the STATE values to DUPE when there exists another row with a higher ID value that has the same NAME and LAST NAME. If so, use this:
update t set STATE = (case when sorted.RowNbr = 1 then null else 'DUPE' end)
from yourtable t
join (select
ID,
row_number() over
(partition by name, [last name], phone order by id desc) as RowNbr from yourtable)
sorted on sorted.ID = t.ID