Case when based on first few characters - sql

I have Table A that looks like this:
Name Phone
John 1111231234
Joe 1111231235
Jack 2221231234
Jenny 2224321234
Jody 3323214211
and Table B that looks like this:
AreaCode
111
111
222
222
How do I return a result that looks like this? I essentially want to return AreaCode if the first 3 numbers/characters from the column 'Phone' exist in the column 'AreaCode' in table B...
Name Phone AreaCode
John 1111231234 111
Joe 1111231235 111
Jack 2221231234 222
Jenny 2224321234 222
Jody 3323214211 null

Use a left join to table b, joining where the phone starts with the areacode:
select
name,
phone,
areacode
from tableA
left join tableB on phone like concat(areacode, '%')

I used distinct to avoid repeated areacodes that will bring you duplicated results.
If you store areacode an phone as numeric you can omit the cast
select a.*, b.AreaCode
from TableA a left join (select distinct areacode from tableb) b
on left(cast(a.Phone as varchar(20)),3)=cast(b.AreaCode as varchar(20))

In teradata, you may need something like this
select
name,
phone,
areacode
from tableA
left join tableB on SUBSTRING(phone FROM 1 FOR 3) = areacode

As some values in column phone exceeds the max allowed limit for INTEGER i.e. 2147483647, so i assume that BIGINT is the datatype. In this case below is the query that will return your desired result.
SELECT DISTINCT t1.Name,
t1.Phone,
t2.areacode
FROM t1
LEFT JOIN t2 ON substring(t1.Phone
FROM 11
FOR 3) = t2.areacode
ORDER BY 3 DESC;
substring impliticitly cast bigint to 20 space variable character left justified as bigint requires 20 character, so the starting point for substring is 11. Also teradata implicitly compare character with INT, so no need to cast areacode
Other option is to use trim before substring to remove leading spaces as below.
SELECT DISTINCT t1.Name,
t1.Phone,
t2.areacode
FROM t1
LEFT JOIN t2 ON substring(trim(t1.Phone)
FROM 1
FOR 3) = t2.areacode
ORDER BY 3 DESC;
DISTINCT is used to avoid duplicates, as area code has duplicate values, so joining it to the phone record table will create duplicate rows.
Result:
Name Phone areacode
----------------------------------
Jack 2,221,231,234 222
Jenny 2,224,321,234 222
Joe 1,111,231,235 111
John 1,111,231,234 111
Jody 3,323,214,211 ?
P.S. As substring and trim functions are same in Teradata and MySQL, you can check the demo here
Hope this will help :-)

Related

Sql Query: How to Base on the row name to display

I have the table data as listed on below:
name | score
andy | 1
leon | 2
aaron | 3
I want to list out as below, even no jacky's data, but list his name and score set to 0
aaron 3
andy 2
jacky 0
leon 2
You didn't specify your DBMS, but the following is 100% standard ANSI SQL:
select v.name, coalesce(t.score, 0) as score
from (
values ('andy'),('leon'),('aaron'),('jacky')
) as v(name)
left join your_table t on t.name = v.name;
The values clause builds up a "virtual table" that contains the names you are interested in. Then this is used in a left join so that all names from the virtual table are returned plus the existing scores from your (unnamed table). For non-existing scores, NULL is returned which is turned to 0 using coalesce()
If you only want to specify the missing names, you can use a UNION in the virtual table:
select v.name, coalesce(t.score, 0) as score
from (
select t1.name
from your_table t1
union
select *
from ( values ('jacky')) as x
) as v(name)
left join your_table t on t.name = v.name;
fixed the query, could list out the data, but still missing jacky, only could list out as shown on below, the DBMS. In SQL is SQL2008.
data
name score scoredate
andy 1 2021-08-10 01:23:16
leon 2 2021-08-10 03:25:16
aaron 3 2021-08-10 06:25:16
andy 4 2021-08-10 11:25:16
leon 5 2021-08-10 13:25:16
result set
name | score
aaron | 1
andy | 5
leon | 7
select v.name as Name,
coalesce(sum(t.score),0) as Score
from (
values ('aaron'), ('andy'), ('jacky'), ('leon')
) as v(name)
left join Score t on t.name=v.name
where scoredate>='2021-08-10 00:00:00'
and scoredate<='2021-08-10 23:59:59'
group by v.name
order by v.name asc
Your question lacks a bunch of information, such as where "Jacky"s name comes from. If you have a list of names that you know are not in the table, just use union all:
select name, score
from t
union all
select 'Jacky', 0;

How to know if a value matches one value or another but not both SQL

Hey, I have a question regarding an "xor" in SQL
I need to know if a value if one column matches one of the two given values but not both, for example, need to return the names of those who match Dollar or Euro, but not both, they can match other currencies.
Name | Currency
---------------
John | Dollar
John | Euro
John | Dollar
Peter| Euro
Peter| Pound
Bob | Dollar
In this example I need to return both Peter and Bob.
I have tried symmetric difference, the union of those who have dollars and euros minus the intersection, but it is a big chunk of code and not working properly. Thanks!
here is one way , using group by :
SELECT *
FROM curenncyname c1
WHERE NOT EXISTS (
SELECT name , Currency, COUNT(*)
FROM urenncyname c2
WHERE c2.name = c1.name
GROUP BY name , Currency
HAVING COUNT(*) > 1
)
You can use aggregation:
SELECT name
FROM t
WHERE currency IN ('Dollar', 'Euro')
GROUP BY name
HAVING MIN(currency) = MAX(currency);
Of, if you like, you can use set operators:
select name
from t
where currency in ('Dollar', 'Euro')
minus
(select name
from t
where currency in ('Dollar')
intersect
select name
from t
where currency in ('Euro')
);
Another way to use it is to use a FULL JOIN with an appropriate filter in the WHERE clause:
SELECT COALESCE(d.NAME, e.NAME)
FROM (SELECT * FROM SOME_TABLE WHERE CURRENCY = 'Dollar') d
FULL OUTER JOIN (SELECT * FROM SOME_TABLE WHERE CURRENCY = 'Euro') e
ON e.Name = d.Name
WHERE (e.Name IS NULL AND d.Name IS NOT NULL) OR
(e.Name IS NOT NULL AND d.Name IS NULL)
This returns
Peter
Bob
db<>fiddle here

SQL - how to transpose only some row values into column headers without pivot

I have a table similar to this:
stud_ID | first_name | last_name | email | col_num | user_value
1 tom smith 50 Retail
1 tom smith 60 Product
2 Sam wright 50 Retail
2 Sam wright 60 Sale
but need to convert it to: (basically transpose 'col_num' to column headers and change 50 to function, 60 to department)
stud_ID | first_name | last_name | email | Function | Department
1 tom smith Retail Product
2 Sam wright Retail Sale
Unfortunately Pivot doesn't work in my system, just wondering if there is any other way to do this please?
The code that I have so far (sorry for the long list):
SELECT c.person_id_external as stu_id,
c.lname,
c.fname,
c.mi,
a.cpnt_id,
a.cpnt_typ_id,
a.rev_dte,
a.rev_num,
cp.cpnt_title AS cpnt_desc,
a.compl_dte,
a.CMPL_STAT_ID,
b.cmpl_stat_desc,
b.PROVIDE_CRDT,
b.INITIATE_LEVEL1_SURVEY,
b.INITIATE_LEVEL3_SURVEY,
a.SCHD_ID,
a.TOTAL_HRS,
a.CREDIT_HRS,
a.CPE_HRS,
a.CONTACT_HRS,
a.TUITION,
a.INST_NAME,
--a.COMMENTS,
a.BASE_STUD_ID,
a.BASE_CPNT_TYP_ID,
a.BASE_CPNT_ID,
a.BASE_REV_DTE,
a.BASE_CMPL_STAT_ID,
a.BASE_COMPL_DTE,
a.ES_USER_NAME,
a.INTERNAL,
a.GRADE_OPT,
a.GRADE,
a.PMT_ORDER_TICKET_NO,
a.TICKET_SEQUENCE,
a.ORDER_ITEM_ID,
a.ESIG_MESSAGE,
a.ESIG_MEANING_CODE_ID,
a.ESIG_MEANING_CODE_DESC,
a.CPNT_KEY,
a.CURRENCY_CODE,
c.EMP_STAT_ID,
c.EMP_TYP_ID,
c.JL_ID,
c.JP_ID,
c.TARGET_JP_ID,
c.JOB_TITLE,
c.DMN_ID,
c.ORG_ID,
c.REGION_ID,
c.CO_ID,
c.NOTACTIVE,
c.ADDR,
c.CITY,
c.STATE,
c.POSTAL,
c.CNTRY,
c.SUPER,
c.COACH_STUD_ID,
c.HIRE_DTE,
c.TERM_DTE,
c.EMAIL_ADDR,
c.RESUME_LOCN,
c.COMMENTS,
c.SHIPPING_NAME,
c.SHIPPING_CONTACT_NAME,
c.SHIPPING_ADDR,
c.SHIPPING_ADDR1,
c.SHIPPING_CITY,
c.SHIPPING_STATE,
c.SHIPPING_POSTAL,
c.SHIPPING_CNTRY,
c.SHIPPING_PHON_NUM,
c.SHIPPING_FAX_NUM,
c.SHIPPING_EMAIL_ADDR,
c.STUD_PSWD,
c.PIN,
c.PIN_DATE,
c.ENCRYPTED,
c.HAS_ACCESS,
c.BILLING_NAME,
c.BILLING_CONTACT_NAME,
c.BILLING_ADDR,
c.BILLING_ADDR1,
c.BILLING_CITY,
c.BILLING_STATE,
c.BILLING_POSTAL,
c.BILLING_CNTRY,
c.BILLING_PHON_NUM,
c.BILLING_FAX_NUM,
c.BILLING_EMAIL_ADDR,
c.SELF_REGISTRATION,
c.SELF_REGISTRATION_DATE,
c.ACCESS_TO_ORG_FIN_ACT,
c.NOTIFY_DEV_PLAN_ITEM_ADD,
c.NOTIFY_DEV_PLAN_ITEM_MOD,
c.NOTIFY_DEV_PLAN_ITEM_REMOVE,
c.NOTIFY_WHEN_SUB_ITEM_COMPLETE,
c.NOTIFY_WHEN_SUB_ITEM_FAILURE,
c.LOCKED,
c.PASSWORD_EXP_DATE,
c.SECURITY_QUESTION,
c.SECURITY_ANSWER,
c.ROLE_ID,
c.IMAGE_ID,
c.GENDER,
c.PAST_SERVICE,
c.LST_UNLOCK_TSTMP,
c.MANAGE_SUB_SP,
c.MANAGE_OWN_SP,
d.col_num,
d.user_value
FROM pa_cpnt_evthst a,
pa_cmpl_stat b,
pa_student c,
pv_course cp,
pa_stud_user d
WHERE a.cmpl_stat_id = b.cmpl_stat_id
AND a.stud_id = c.stud_id
AND cp.cpnt_typ_id(+) = a.cpnt_typ_id
AND cp.cpnt_id(+) = a.cpnt_id
AND cp.rev_dte(+) = a.rev_dte
AND a.CPNT_TYP_ID != 'SYSTEM_PROGRAM_ENTITY'
AND c.stud_id = d.stud_id
AND d.col_num in ('10','30','50','60')
I would just use conditional aggregation:
select stud_ID, first_name, last_name, email,
max(case when col_num = 50 then user_value end) as function,
max(case when col_num = 60 then user_value end) as department
from t
group by stud_ID, first_name, last_name, email;
Your code seems to have nothing to do with the sample data. I do notice however that you are using implicit join syntax. You really need to learn how to use proper, explicit, standard JOIN syntax.
I'm assuming you have Sql Server 2000 or 2003. What you need to do in that case is create a script with one cursor.
This cursor will create a text with something like this:
string var = "CREATE TABLE #Report (Col1 VARCHAR(20), Col2, VARCHAR(20), " + ColumnName
That way you can create a temp table on the fly, at the end you will need to do a Select of your temp table to get your pivot table ready.
Its not that easy if you are not familiar with cursors.
OR
if there are only few values on your 'pivot' column and they are not going to grow you can also do something like this:
Pivot using SQL Server 2000
I'm unable to understand your code, so I'll just assume the table mentioned in the sample data as stud(because of stud_id).
So here is what I think can do the work of pivot.
SELECT ISNULL(s1.stud_ID, s2.stud_id),
ISNULL(s1.first_name, s2.first_name),
ISNULL(s1.last_name, s2.last_name),
ISNULL(s1.email, s2.email),
s1.user_value as [Function], s2.user_value as Department
FROM stud s1 OUTER JOIN stud s2
ON s1.stud_ID = s2.stud_ID -- Assuming stud_ID is primary key, else join on all primary keys
AND s1.col_num = 50 AND s2.col_num = 60
Explanation: I'm just trying to simulate here what PIVOT does. For every column you want, you create a new table in the JOIN and constaint it to only one value in your col_num column. For example, if there are no values for 50 in s1, the OUTER JOIN will get make it NULL and we need to pull records from s2.
Note: If you need more than 2 new columns, then you can use COALESCE instead of ISNULL

How to get a correlated subquery as column

I dont know how I can do this sql query, probably its simple but I don't know how i can do it.
I have 2 tables:
Table_Articles:
COD NAME
1 Bottle
2 Car
3 Phone
Table_Articles_Registered
COD_ARTICLE DATE
1 05/11/2014
1 06/11/2014
1 07/11/2014
2 08/11/2014
2 09/11/2014
3 05/11/2014
I want take in the table Table_Articles_Registered the row with the MAX date , finally I want get this result:
COD NAME DATE
1 Bottle 07/11/2014
2 Car 09/11/2014
3 Phone 05/11/2014
I need use the sencente like this. The problem its in the subquery. Later I use other inner join in the sentence, this is only a fragment.
select
_Article.Code,
_Article.Description ,
from Tbl_Articles as _Article left join
(
select top 1 *
from ArticlesRegisterds where DATE_REGISTERED <= '18/11/2014'
order by DATE_REGISTERED
)
as regAux
on regAux.CODE_ARTICLE= _Article.CODE
I dont know how can I connect the field CODE_ARTICLE in the table ArticlesRegisterds with the first query.
I think this is a basic aggregation query with a join:
select a.cod, a.name, max(ar.date) as date
from Artiles a join
ArticlesRegisterds ar
on ar.cod_article = a.cod
group by a.cod, a.name
Try this:-
SELECT TAR.COD_ARTICLE, TA.NAME, MAX(TAR.DATE)
FROM Table_Articles_Registered TAR JOIN
Table_Articles.TA ON TAR.COD_ARTICLE = TA.COD
GROUP BY TAR.COD_ARTICLE, TA.NAME;
Can't you just do this?:
SELECT
Table_Articles.COD,
Table_Articles.NAME,
(
SELECT MAX(Table_Articles_Registered.DATE)
FROM Table_Articles_Registered
WHERE Table_Articles.COD_ARTICLE=Table_Articles.COD
) AS DATE
FROM
Table_Articles

Query to fetch records from 2 diff table into 2 columns

I have 2 table like below :
1)
Engine
======
ID Title Unit Value
123 Hello Inch 50
555 Hii feet 60
2)
Fuel
=====
ID Title Value
123 test12 343
555 test5556 777
I want the select result in 2 columns as per the ID given (ID should be same in both tables) :
Title -- This will get the (Title + Unit) from Engine table and only
Title from Fuel table. Value
Value-- This will get Value from both tables.
Result for ID = 123 is :
Title Value
Hello(Inch) 50
test12 343
Any suggestion how I can get this in SQL server 2008.
Based on your same data and the desired result, it appears that you want to use a UNION ALL to get the data from both tables:
select title+'('+Unit+')' Title, value
from engine
where id = 123
union all
select title, value
from fuel
where id = 123
See SQL Fiddle with Demo
The result of the query is:
| TITLE | VALUE |
-----------------------
| Hello(Inch) | 50 |
| test12 | 343 |
Look at SQL JOINs: INNER JOIN, LEFT JOIN etc
Select
e.ID, e.Title, e.Unit, e.Value, f.Title as FuelTitle, e.Value as FuelValue,
e.Title+' '+e.Units As TitleAndUnits
From Engine e
Join Fuel f
On e.ID = f.ID
You can do this w/o a join but with join it may be more optimal depending on other factors in your case.
Example w/o join:
select concat(t1.c1, ' ', t1.c2, ' ', t2.c1) col1, concat(t1.c3, ' ', t2.c3) col2
from t1, t2
where t1.id = [ID] and t2.id = [ID]
You should probably have a look at something like Introduction to JOINs – Basic of JOINs and read up a little on JOINS
Join Fundamentals
SQL Server Join Example
SQL Joins
EDIT
Maybe then also look at
CASE (Transact-SQL)
+ (String Concatenation) (Transact-SQL)
CAST and CONVERT (Transact-SQL)