sql conversions in select statement - sql-server

Here is a table example. using sql-server
I am trying to pull the max(login date) for each employee below, but the "login date" in the database is datatype int.
I can select it easy enough, ie,
select employee,title,max(login_date) from employee group by employee,title
I can use substring to convert the login_date("YYYYMM") to a date variable,
set #var_year=select (substring((select login_date),1,4))
using a variable to store the year and a variable to store the month, but how do I pass that to my main select statement?
Employee Title Login_Date
-----------------------------------------
Mike VP 201301
Amy CEO 201201
Joe Office Mgr 201105
Andy Admin Asst 201308
Joe Office Mgr 201205
Andy Admin Asst 201309
Joe Office Mgr 201205
Andy Admin Asst 201309

A few ways you could do that.
One would be
Select m.employee,m.title,
convert(int,substring(thisisNOTadate,1,4)) as [Year],
convert(int,substring(thisisNOTadate,5,2)) as [Month]
From
(select employee,title,max(login_date) as ThisisNOTadate
from employee group by employee,title
) m
Personally after slapping who ever called a string in the format YYYYMM login_date a few times, I'd rework the table so login_date was in fact a date with something like Convert(DateTime,Convert(VarChar(6), Login_date) + '01'), and then anything that needed parts of the date could use that standard date functions.
So based on your comment to Mr ReBand earlier then
select employee,title,
max(convert(datetime,Convert(varchar(6),login_date) + '01')) as arealdate
From employee group by employee,title
would be another.

Related

Snowflake Extracting Month, year from date

I have a table with a column called created_date that has date like 2020-01-01 00:00:00.000
and I'm trying to create a column that will show only the year, another one the month
and one that shows the month as a string
here what I try
select date_part(year,'created_date ') as year,
date_part(month, 'created_date ') as month
to_char(Month, 'created_date') as month_name,
user_name,
product
from user_table
Unfortunately when running the query above, I get an error that Function Extract do not support VARCHAR(10) argument type
The result I'm trying to get is to who a table like
year month month_name user_name product
2021 01 January John Doe Ninja Mixer
2021 05 May Clide Smith Blender
Any help will be appreciated as I'm mostly used to MS sql and we just switch to snowflake.
Assuming the "created_date" is stored as a timestamp or datetime (synonyms), then you just need to remove the single quotes from around the created_date column name and change "to_char" to use the "monthname" function:
select date_part(year, created_date) as year,
date_part(month, created_date) as month,
monthname(created_date) as month_name,
user_name,
product
from user_table

Query for date groupings?

I have a Client table with basic demographics in rows and a date of birth row (DOB) with a DATE data type.
I'm trying to make a query that will take my entries and count how many clients are between the ages of 18-60, 61-79, 80+. I'm not sure if I'm having a brain-fart, but I can't figure out how to gather that info from my table...
So what I have is:
Last Name First Name DOB
Stein Ethel 1954-01-20
Frank Sam 1981-05-65
etc...
What I want to have is:
Ages 18-60
6
Ages 61-79
10
Ages 80+
20
Any recommendations to proceed?
Using #Alex's suggestion
declare #today datetime
set #today =getdate()
select
s as [start],
e as [end],
count(1) as [count]
from Client join
(values (0,17),(18,60),(61,79),(80,9999)) as ranges(s,e)
on datediff(yy,dob,#today) between s and e
-- where buildingid=1
group by s,e
See demo here

Delete latest entry in SQL Server without using datetime or ID

I have a basic SQL Server delete script that goes:
Delete from tableX
where colA = ? and colB = ?;
In tableX, I do not have any columns indicating sequential IDs or timestamp; just varchar. I want to delete the latest entry that was inserted, and I do not have access to the row number from the insert script. TOP is not an option because it's random. Also, this particular table does not have a primary key, and it's not a matter of poor design. Is there any way I can do this? I recall mysql being able to call something like max(row_number) and also something along the lines of limit one.
ROW_NUMBER exists in SQL Server, too, but it must be used with an OVER (order_by_clause). So... in your case it's impossible for you unless you come up with another sorting algo.
MSDN
Edit: (Examples for George from MSDN ... I'm afraid his company has a Firewall rule that blocks MSDN)
SQL-Code
USE AdventureWorks2012;
GO
SELECT ROW_NUMBER() OVER(ORDER BY SalesYTD DESC) AS Row,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0;
Output
Row FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
Returning a subset of rows
USE AdventureWorks2012;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
FROM Sales.SalesOrderHeader
)
SELECT SalesOrderID, OrderDate, RowNumber
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
Using ROW_NUMBER() with PARTITION
USE AdventureWorks2012;
GO
SELECT FirstName, LastName, TerritoryName, ROUND(SalesYTD,2,1),
ROW_NUMBER() OVER(PARTITION BY TerritoryName ORDER BY SalesYTD DESC) AS Row
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0
ORDER BY TerritoryName;
Output
FirstName LastName TerritoryName SalesYTD Row
--------- -------------------- ------------------ ------------ ---
Lynn Tsoflias Australia 1421810.92 1
José Saraiva Canada 2604540.71 1
Garrett Vargas Canada 1453719.46 2
Jillian Carson Central 3189418.36 1
Ranjit Varkey Chudukatil France 3121616.32 1
Rachel Valdez Germany 1827066.71 1
Michael Blythe Northeast 3763178.17 1
Tete Mensa-Annan Northwest 1576562.19 1
David Campbell Northwest 1573012.93 2
Pamela Ansman-Wolfe Northwest 1352577.13 3
Tsvi Reiter Southeast 2315185.61 1
Linda Mitchell Southwest 4251368.54 1
Shu Ito Southwest 2458535.61 2
Jae Pak United Kingdom 4116871.22 1
Your current table design does not allow you to determine the latest entry. YOu have no field to sort on to indicate which record was added last.
You need to redesign or pull that information from the audit tables. If you have a database without audit tables, you might have to find a tool to read the transaction logs and it will be a very time-consuming and expensive process. Or if you know the date the records you want to remove were added, you could possibly use a backup from just before this happened to find the records that were added. Just be awwre that you might be looking at records changed after this date that you want to keep.
If you need to do this on a regular basis instead of one-time to fix some bad data, then you need to properly design your database to include an identity field and possibly a dateupdated field (maintained through a trigger) or audit tables. (In my opinion no database containing information your company is depending on should be without audit tables, one of the many reasons why you should never allow an ORM to desgn a database, but I digress.) If you need to know the order records were added to a table, it is your responsiblity as the developer to create that structure. Databases only store what is deisnged for tehm to store, if you didn't design it in, then it is not available easily or at all
If (colA +'_'+ colB) can not be dublicate try this.
declare #delColumn nvarchar(250)
set #delColumn = (select top 1 DeleteColumn from (
select (colA +'_'+ colB) as DeleteColumn ,
ROW_NUMBER() OVER(ORDER BY colA DESC) as Id from tableX
)b
order by Id desc
)
delete from tableX where (colA +'_'+ colB) =#delColumn

SSRS - Grouping multiple rows per page based on varchar column

I'm trying to create an SSRS report that will display all timesheets per person, per accounting period (month) on a single page. However, I'm stuggling to work out how the result should be grouped. So far all I seem to be able to do is get one line to appear per specified user per page.
My T-SQL looks like this:
SELECT tblADSI.DisplayName AS FullName,
ds.[Date of Work],
ds.Hours,
ds.[Description of Work],
ds.Mileage,
ds.Subsistence,
ds.[Activity Code] AS CompanyRef,
c.[Cost Center] AS DiaryClient,
r.Role,
c.Description AS Project,
ds.[Accounting Period],
ds.[Rechargeable Items]
FROM [Diary Sheets] ds
LEFT JOIN Commissions c on c.[Commission Code] = ds.[Commission Code]
LEFT JOIN dbo.Roles r on r.Commission = ds.[Commission Code] and r.EmployeeID = ds.EmployeeID
LEFT JOIN [Accounting Period] ap ON ap.ID = ds.[Accounting Period ID]
LEFT JOIN (SELECT displayName,
EmployeeID FROM OpenQuery (
ADSI,
'SELECT
displayName,
EmployeeID
FROM ''LDAP://example.domaincontroller.com/OU=Unit1,DC=domaincontroller,DC=com''
WHERE objectCategory = ''person''
AND objectClass = ''User''
') AS tblADSI
UNION
SELECT displayName,
EmployeeID
FROM OpenQuery (
ADSI,
'SELECT
displayName,
EmployeeID
FROM ''example.domaincontroller.com/OU=Unit2,DC=domaincontroller,DC=com''
WHERE objectCategory = ''person''
AND objectClass = ''User''
') AS tblADSI
) AS tblADSI
ON tblADSI.EmployeeID = ds.employeeID
WHERE c.[Commission Code] = 'Example Commission'
AND ap.[Accounting Period] = 'Febuary 2015'
ORDER BY FullName, ds.[Date of Work], ds.[Activity Code]
An example output from the SQL would be.
-- Name Date Of Work Hours
John Smith 01/02/2015 9
John Smith 02/02/2015 10
Jane Doe 01/02/2015 5
Jane Doe 02/02/2015 5
Mike Smith 01/02/2015 8
Mike Smith 02/02/2015 9
So using the SQL above as my example I've built a report which should display per page every user (based on the commission parameter set by the users) within a particular commission. However, all that seems to be happening in the report is it shows one row (the most recent entry for the February accounting period) and nothing more. For example:
-- Name Date Of Work Hours
John Smith 01/02/2015 9
Jane Doe 01/02/2015 5
Mike Smith 01/02/2015 8
I actually need it to show all diary sheets for the accounting period per user so in the report, using John Smith as the example, it would appear as so:
-- Name Date Of Work Hours
John Smith 01/02/2015 9
John Smith 02/02/2015 10
And so on and so forth for every other user on a new page.
Does anybody know how I can achieve this? I've looked into and tried some SSRS grouping (which I suspect is the solution) but I'm completely at a loss. No matter what type of grouping I try it always comes out the same.
I've been writing SQL for a couple of years, but I'm relatively new to SSRS and my SSRS knowledge completely self taught so some of my terminology/formatting is probably incorrect.
I managed to fix it by adding all columns from my SELECT statement as parent row groups on my tablix. Thanks mxix and NickyvV for your suggestions, much appreciated.

SQL Query that can return intersecting data

I have a hard time finding a good question title - let me just show you what I have and what the desired outcome is. I hope this can be done in SQL (I have SQL Server 2008).
1) I have a table called Contacts and in that table I have fields like these:
FirstName, LastName, CompanyName
2) Some demo data:
FirstName LastName CompanyName
John Smith Smith Corp
Paul Wade
Marc Andrews Microsoft
Bill Gates Microsoft
Steve Gibbs Smith Corp
Diane Rowe ABC Inc.
3) I want to get an intersecting list of people and companies, but companies only once. This would look like this:
Name
ABC Inc.
Bill Gates
Diane Rowe
John Smith
Marc Andrews
Microsoft
Smith Corp
Steve Gibbs
Paul Wade
Can I do this with SQL? How?
You take all the person names, and then also add all the companies
SELECT CONCAT([First Name],' ',[Last Name]) AS Name FROM Contacts
UNION ALL
SELECT DISTINCT CompanyName FROM Contacts
WHERE CompanyName IS NOT NULL
The DISTINCT keyword ensures that companies are output only once, and the WHERE
clause removes rows where no company info is known.
If a person has the same name as a company, then this will output a duplicate. If you don't want that, then change UNION ALL to UNION, and any name will be output only once.
I'm not sure what you mean by "intersecting," but you can easily get the results you describe as the union of two queries against that same table.
select
t.firstname + ' ' + t.lastname
from
mytable t
union
select
t.company
from
mytable t
Edit: UNION should make each SELECT distinct by default.
Does this do what you need?
SELECT FirstName + ' ' + LastName AS Name
FROM Contacts
UNION
SELECT CompanyName
FROM Contacts
(The UNION rather than UNION ALL will ensure distinctness of both top and bottom parts. mdma's answer will work if you do need the possibility of duplicate people names. You might need to add an ORDER BY Name depending on your needs)

Resources