How to view different data depending on the value for SQL - sql

How can I make the values show up differently?
Example:
I have a table 'Feelings' with a column called 'Happy'
If I select * from 'Happy' it will bring back values 1, 2, 3 (with user IDs to show which user is which feeling)
1 stands for Yes, 2 stands for no, 3 stands for maybe
I want the table to not show 1,2,3 but instead show yes,no,maybe
How would I go about to making this?

CASE HAPPY
WHEN '1' THEN 'Yes'
WHEN '2' THEN 'No'
WHEN '3' THEN 'Maybe'
ELSE 'Other'
END AS 'Happy'

While you can use a CASE as other answers here you can also use a join -- to a table of lookup values or to a CTE, or VALUES clause. Even a temp table in a stored procedure.
That would look like this:
SELECT user_id, COALESCE(lookup.value,'Unknown') as happy
FROM feelings
LEFT JOIN (
VALUES
('1','Yes'),
('2','No'),
('3','Maybe')
) AS lookup(k,value) ON feelings.happy = lookup.k
Using a join and storing related information in a table is a much more SQL way of doing things and offers many benefits including easier maintenance and often faster execution.

If you just have a table called Feelings and a column called Happy with just IDs, you can try the following query:
SELECT
user_id,
CASE HAPPY
WHEN '1' THEN 'Yes'
WHEN '2' THEN 'No'
WHEN '3' THEN 'Maybe'
ELSE 'Other'
END AS 'feeling_happy'
FROM FEELINGS
Otherwise, if you have 2 tables, one called Feelings with column Happy that has the IDs and another table called Happy with the IDs in one column and the defined statuses in another column (which we'll call happy_x), then you can simple use the following query:
SELECT
f.user_id, h.happy_x
FROM Feelings f
INNER JOIN Happy AS h
ON h.id = f.happy

Related

Validate my interpretation of an SQL query

my question is definitely going to be a little different, so I hope I'm still adhering to the stack overflow question etiquette. With that in mind, I'll get straight to the point.
Essentially, since I am still learning SQL I was looking at examples of scheduled queries in GCP and came across something and I wanted to see if I understand what's going on. So I took the query and wrote some comments explaining what I think the lines in the query are doing. The context in the code itself is irrelevant, I'm more curious if I'm correctly understanding what each of the clauses is doing.
Would anyone be able to tell me if I am interpreting it correctly or if I misunderstood some stuff, based on my comments? The code and comments are below. Note that the comments come first and the queries I'm commenting on follow directly after.
-- Create temporary table with the subquery below via the WITH () clause
-- Table contains session date, which webpage, total sessions, total sessions with a logout, and total clicks
-- The data in this temporary table is coming from the `gcp-project-223467.web.top_level` table in BigQuery
-- The columns correspond to dates 01/01/2022 & onwards, and exclude the 'Home'and 'Team' pages
-- The resulting data in the temp table is grouped by date & page type (first and second columns of the resulting temp table)
WITH logins AS (
SELECT
session_date as date,
website_page as page,
SUM(sessions) AS sessions,
SUM(sessions_with_logout) AS logouts,
SUM(clicks) AS clicks
FROM `gcp-project-223467.web.top_level`
WHERE DATE_session >= "2022-01-01"
AND website_page NOT IN ('Home','Team')
AND clicks > 0
GROUP BY 1, 2
)
-- Select the data from the above subquery (via SELECT logins.*)
-- Left join another temp table with data coming from `ingka-web-analytics-prod.web_data.transactions` in BigQuery
-- Left join is being done according to the logins & login_days date_hit AND logins & login_days ´logins_web´ columns.
-- The specific data taken from the aforementioned BQ table is aggregated and filtered via CASE WHEN - THEN statements
-- Further conditions are specified via the WHERE statements
-- The resulting temporary table in the subquery under LEFT JOIN is named login_days.
-- The columns in the select statement before the left join (web logins, mobile logins etc)
-- are from the temporary table in the select statement under the left join statement
SELECT
logins.*,
logins_web,
mobile_logins,
logins_ios,
logins_android,
logins_final
FROM logins
LEFT JOIN (
SELECT
date_hit as date,
website_page as page,
SUM(CASE WHEN login_type = 'web' THEN SAFE_CAST(count_logins_final AS INT64) END ) AS logins_web,
COUNT(DISTINCT CASE WHEN login_type = 'mobile' THEN login_id END ) AS mobile_logins,
SUM(CASE WHEN login_type = 'ipad' THEN SAFE_CAST(count_logins_final AS INT64) END ) AS logins_ios,
COUNT(DISTINCT CASE WHEN login_type = 'android' THEN login_id END ) AS logins_android,
COUNT(DISTINCT login_id) AS logins_final,
FROM `gcp-project-223467.web.login_data`
WHERE date_hit >= "2022-01-01" AND website_page NOT IN ('Home','Team')
AND count_logins_final != 'NaN'
AND count_logins_final NOT LIKE '%,%'
AND count_logins_final > '0'
AND website_platform != 'ibes'
AND login_type = 'Successful'
GROUP BY 1, 2
)login_days
ON logins.date = login_days.date AND logins.page = login_days.page
WHERE sessions_with_logout > 0

I need to create a VIEW from an existing TABLE and MAP an additional COLUMN to that VIEW

I am fairly new to SQL. What I am trying to do is create a view from an existing table. I also need to add a new column to the view which maps to the values of an existing column in the table.
So within the view, if the value in a field for Col_1 = A, then the value in the corresponding row for New_Col = C etc
Does this even make sense? Would I use the CASE clause? Is mapping in this way even possible?
Thanks
The best way to do this is to create a mapping or lookup table
For example consider the following LOOKUP table.
COL_A NEW_VALUE
---- -----
A C
B D
Then you can have a query like this:
SELECT A.*, LOOK.NEW_VALUE
FROM TABLEA AS A
JOIN LOOKUP AS LOOK ON A.COL_A = LOOK.COL_A
This is what DimaSUN is doing in his query too -- but in his case he is creating the table dynamically in the body of the query.
Also note, I'm using a JOIN (which is an inner join) so only results in the lookup table will be returned. This could filter the results. A LEFT JOIN there would return all data from A but some of the new columns might be null.
Generally, a view is an instance of a table/a replica provided that there is no alteration to the original table. So, as per your query you can manipulate the data and columns in a view by using case.
Create View viewname as
Select *,
case when column=a.value then 'C'
....
ELSE
END
FROM ( Select * from table) a
If You have restricted list of replaced values You may hardcode that list in query
select T.*,map.New_Col
from ExistingTable T
left join (
values
('A','C')
,('B','D')
) map (Col_1,New_Col) on map.Col_1 = T.Col_1
In this sample You hardcode 'A' -> 'C' and 'B' -> 'D'
In general case You better may to use additional table ( see Hogan answer )

SQL SSMS IF THEN with multiple criteria across same field

I need to pull a transaction record from a table if it is type 'C' and has a record post time greater than or equal to the post time for a record with type 'W' where the account numbers and post date are the same. I am struggling with creating an if/then where the posttime for type 'C' >= posttime for type 'W'... any help would be appreciated. I've done these types before but never for the same field where only one record item is different.
This would be the typical method using exists:
select * from transactions t
where t.actioncode = 'C' and exists (
select 1 from transactions t2
where t2.account_num = t.account_num and t2.postdate = t1.postdate
and t2.actioncode = 'W'
and t2.posttime < t1.posttime
)
If I understand you correctly, what you describe can be accomplished through JOINS.
Think relational data sets and SARGs.
While you still have not given us a table structure (which helps enormously), the solution can help steer you in the right direction. The following assumes a FACT table of TRANSACTIONS, where the carnality to itself is M:M
SELECT TOP 1000 A.ACTIONCODE, A.TRAN_RECORD --, any other needed columns
FROM TRANSACTIONS A
INNER JOIN (SELECT ACTIONCODE, POSTTIME, ACCOUNT_NUM, POSTDATE
FROM TRANSACTIONS
WHERE ACTIONCODE = 'W') B ON A.ACCOUNT_NUM = B.ACCOUNT_NUM
AND A.POSTDATE = B.POSTDATE
WHERE A.ACTIONCODE = 'C'
AND A.POSTTIME >= B.POSTTIME
UPDATED: I accidently forgot to include the correct number of columns. Always specify the same columns (or * if you do not care) that you will be using in your INNER JOIN.
Regardless, we optimize the query by only returning results that we will be using or seeing in our query.
This is what I had originally, but it just churned in SSMS without results. Essentially, I just need all 'C' type records returned where there is a 'W' type record with a posttime less than the 'C', but where the account numbers and postdate for the record are the same. posttime, postdate, type, and number are all fields in my table.
SELECT *
FROM TRANSACTIONS
WHERE ACTIONCODE = 'C' AND POSTTIME >= POSTTIME AND ACTIONCODE = 'W'

Compare comma separated list with individual row in table

I have to compare comma separated values with a column in the table and find out which values are not in database. [kind of master data validation]. Please have a look at the sample data below:
table data in database:
id name
1 abc
2 def
3 ghi
SQL part :
Here i am getting comma separated list like ('abc','def','ghi','xyz').
now xyz is invalid value, so i want to take that value and return it as output saying "invalid value".
It is possible if i split those value, take it in temp table, loop through each value and compare one by one.
but is there any other optimal way to do this ??
I'm sure if I got the question right, however, I would personally be trying to get to something like this:
SELECT
D.id,
CASE
WHEN B.Name IS NULL THEN D.name
ELSE "invalid value"
END
FROM
data AS D
INNER JOIN badNames B ON b.Name = d.Name
--as SQL is case insensitive, equal sign should work
There is one table with bad names or invalid values if You prefer. This can a temporary table as well - depending on usage (a black-listed words should be a table, ad hoc invalid values provided by a service should be temp table, etc.).
NOTE: The select above can be nested in a view, so the data remain as they were, yet you gain the correctness information. Otherwise I would create a cursor inside a function that would go through the select like the one above and alter the original data, if that is the goal...
It sounds like you just need a NOT EXISTS / LEFT JOIN, as in:
SELECT tmp.InvalidValue
FROM dbo.HopeThisIsNotAWhileBasedSplit(#CSVlist) tmp
WHERE NOT EXISTS (
SELECT *
FROM dbo.Table tbl
WHERE tbl.Field = tmp.InvalidValue
);
Of course, depending on the size of the CSV list coming in, the number of rows in the table you are checking, and the style of splitter you are using, it might be better to dump the CSV to a temp table first (as you mentioned doing in the question).
Try following query:
SELECT SplitedValues.name,
CASE WHEN YourTable.Id IS NULL THEN 'invalid value' ELSE NULL END AS Result
FROM SplitedValues
LEFT JOIN yourTable ON SplitedValues.name = YourTable.name

Need help for bit data type

i want to write a generic sql where i want show yes or not if field data type is bit. here i need to check the data type if data type is bit then it should show yes or no based on value 0 or 1.
select stock_code,makeid,modelid,enginesize,automatic,semiautomatic,manual from VehicleInfoForParts
so in my above sql there is bit type fields are automatic,semiautomatic,manual. so here i need to show yes/no but i dont want to hard code anything.
so please guide me what would be the best approach for generic sql statement.
can i join my table with system table called information_schema.columns to fetch filed name , value and data type.
so result would be like
Column_Name Value datatype
------------- ------- --------------
stock_code A112 varchar
automatic 1 bit
semiautomatic 0 bit
manual 1 bit
this type of output can we have just joining my sql with information_schema.columns. if possible then please provide me the right sql which will give me the above sort of output.
thanks
please guide. thanks
You could use case for that:
select case bit_field when 1 then 'yes' else 'no' end as ColumnAlias
...
Create a lookup table for Boolean values.
CREATE TABLE dbo.Boolean
(
Id bit PRIMARY KEY
, YesNo varchar(3) UNIQUE
, TrueFalse varchar(10)
)
INSERT INTO dbo.Boolean VALUES (0, 'No', 'False')
INSERT INTO dbo.Boolean VALUES (1, 'Yes', 'True')
Then join to the Boolean table for each bit column.
SELECT v.stock_code, v.makeid, v.modelid, v.enginesize
, a.YesNo automatic, s.YesNo semiautomatic, m.YesNo manual
FROM dbo.VehicleInfoForParts v
LEFT OUTER JOIN dbo.Boolean a ON a.Id = v.automatic
LEFT OUTER JOIN dbo.Boolean s ON s.Id = v.semiautomatic
LEFT OUTER JOIN dbo.Boolean m ON m.Id = v.manual
I recommend doing this in your application, not in the database. When you load your data from SQL Server into, say, an object in your application, handle this in the ToString method of the field you use for your database bit column (assuming you use .NET, if not, use something similar).
You can use the implicit conversion:
select stock_code,makeid,modelid,enginesize,
CASE WHEN automatic = 1 THEN 'Yes' ELSE 'No' END as automatic,
CASE WHEN semiautomatic = 1 THEN 'Yes' ELSE 'No' END as semiautomatic,
CASE WHEN manual = 1 THEN 'Yes' ELSE 'No' END as manual
from VehicleInfoForParts