How to structure these SQL queries so they are perfect SQL? - sql

I have to structure these queries so they are perfect SQL. The queries need to be for a SQL Server database, I have a database StoresDB, a table items_table.
I need to retrieve the
total number of items within this table
The number of item where the price is higher or equal than £10 - the column name is amount
The list of items in the computer category - column name ='comp_id' sorted by decreased amount.
For the above requests I have attempted the below:
SELECT COUNT(*) FROM items_table
Select * from items_table where amount >= 10
Select * from items_table where comp_id = ’electronics’ desc
I am very new to SQL and not sure if I have attempted this correctly.

Maybe is good to know few things when writing this sort of query:
a) SELECT COUNT(*) FROM items_table
This query is written correctly.
b) SELECT COUNT(*) FROM items_table WHERE amount >= 10
Query is OK, but choose to create indexes which cover WHERE clause, in this case, is good to have non-clustered index on amount column
c) SELECT * FROM items_table WHERE comp_id = 'electronics' ORDER BY price DESC
With this last query you have an issue that searching all columns in result, with SELECT * ... which is considered like bad practice in production, so you need to put in SELECT list only columns which are really needed, not all columns. Also you can create non-clustered index on comp_id column, with included columns from SELECT list.

a) Looks correct.
b) You are being asked for a count but are querying a list.
SELECT COUNT(*) FROM items_table WHERE price >= 10
c) This one looks good but you are missing an ORDER BY statement.
SELECT * FROM items_table WHERE catID='electronics' ORDER BY price DESC

Related

Fetch No oF Rows that can be returned by select query

I'm trying to fetch data and showing in a table with pagination. so I use limit and offset for that but I also need to show no of rows that can be fetched from that query. Is there any way to get that.
I tried
resultset.last() and getRow()
select count(*) from(query) myNewTable;
These two cases i'm getting correct answer but is it correct way to do this. Performance is a concern
We can get the limited records using below code,
First, we need to set how many records we want like below,
var limit = 10;
After that sent this limit to the below statement
WITH
Temp AS(
SELECT
ROW_NUMBER() OVER( primayKey DESC ) AS RowNumber,
*
FROM
myNewTable
),
Temp2 AS(
SELECT COUNT(*) AS TotalCount FROM Temp
)
SELECT TOP limit * FROM Temp, Temp2 WHERE RowNumber > :offset order by RowNumber
This is run in both MSSQL and MySQL
There is no easy way of doing this.
1. As you found out, it usually boils down to executing 2 queries:
Executing SELECT with limit and offset in order to fetch the data that you need.
Executing a COUNT(*) in order to count the total number of pages.
This approach might work for tables that don't have a lot of rows, or when you filter the data (int the COUNT and SELECT queries) on a column that is indexed.
2. If your table is large, but the data that you need to show represents smaller percentage of the data from the table and the data shares a common trait (for example, the data in all of your pages is created on a single day) you can use partitioning. Executing COUNT and SELECT on a single partition will be way more faster than executing them on the whole table.
3. You can create another table which will store the value of the COUNT query.
For example, lets say that your big_table table looks like this:
id | user_id | timestamp_column | text_column | another_text_column
Now, your SELECT query looks like this:
SELECT * FROM big_table WHERE user_id = 4 ORDER BY timestamp_column LIMIT 20 OFFSET 20;
And your count query:
SELECT COUNT(*) FROM table WHERE user_id = 4;
You could create a count_table that will have the following format:
user_id | count
Once you fill this table with the current data in the system, you will create a trigger which will update this table on every insert or update of the big_table.
This way, the count query will be really fast, because it will be executed on the count_table, for example:
SELECT count FROM count_table WHERE user_id = 4
The drawback of this approach is that the insert in the big_table will be slower, since the trigger will fire and update the count_table on every insert.
This are the approaches that you can try but in the end it all depends on the size and type of your data.

single SQL query with total records and pagination

I've a query that pulls records based on the search parameter, and I want query to return total records as well as paginate based on start and end, do I've to run two queries or is there more intuitive way to do in a single query.
SELECT * FROM page WHERE article_id = ? AND content like '%#%' //replacing # with keyword
Edit:
Looking for Standard SQL (using WebSQL actually)
This query will return for each row the total of records and the actual page (considering there is 5 rows per page)
select *, count(*) as total, (seq - MOD(seq, 5)) / 5
from (select id, row_number() over(order by id) as seq
from page) a
join page b on b.id = a.id;
Note that this query will works only for Oracle since you did not specify your DBMS I decided by myself so you might have to edit.
Try to use a subquery
count * from table where (select .....)

SQL select column value with biggest number of duplicates

I am having a problem I can't seem to solve. I have a data table that looks like this:
Example:
http://i.stack.imgur.com/tbKEk.png
I need to select the ID_JOB value which is duplicated the most. In this particular example it would be ID_JOB = 1.
Adapt this to your specific SQL implementation. Substitute [job_table] with the table you are querying.
SELECT TOP 1 ID_JOB
FROM job_table
GROUP BY ID_JOB
ORDER BY COUNT(*) DESC
You may need to add more ORDER BY logic in case a count "ties".

How do I make this SQL code faster?

Everyone want me to be more specific. I am attempting to do pagination with asp classic and ms-access database. This is the query I am using to get the items for page 2. there are 25 items per page and when the query returns larger data sets like around 500+ this is taking about 20+ seconds to execute and yes I have made sku indexed for faster queries. any suggestions.
SELECT TOP 25 *
FROM catalog
WHERE sku LIKE '1W%'
AND sku NOT IN (SELECT TOP 25 sku
FROM catalog
WHERE sku LIKE '1W%' ORDER BY price DESC ) ORDER BY price DESC
TOP without ORDER BY looks useless or at least strange. I guess youo meant to use this subquery:
( SELECT TOP 25 sku
FROM catalog
WHERE sku LIKE '1W%'
ORDER BY sku
)
Add an index on sku, if you haven't one.
A possible rewriting of the query, for Access:
SELECT *
FROM catalog
WHERE sku LIKE '1W%'
AND sku >= ( SELECT MAX(sku)
FROM ( SELECT TOP 26 sku
FROM catalog
WHERE sku LIKE '1W%'
ORDER BY sku
)
)
If you are using SQL-Server, you can use window functions for this type of query.
Some pointers:
You can simulate a SELECT BOTTOM (n) by using TOP (n) and reversing the ORDER BY
You can use nested SELECTs (creating a temporary table)
So, the final result of the "paging" query is (replace 50 with 75, 100, 125, ... for subsequent pages):
SELECT TOP 25 *
FROM
(
SELECT TOP 50 *
FROM catalog
WHERE sku LIKE '1W%'
ORDER BY price desc
)
TEMP
ORDER BY price asc;
Although you mentioned you've indexed your data, but, just to be completely clear, for optimal performance, you should ensure all your table is adequately indexed for your query. In this case, I would recommend, AT LEAST the two columns involved in the query:
CREATE INDEX IX_CATALOG ON CATALOG (SKU, PRICE);
What you're trying to do is select all the rows from a table, that meet a certain criteria, other than the first twenty-five. Unfortunately, different database management systems have their own syntax for doing this kind of thing.
There is a good survey of the different syntaxes on the Wikipedia page for the SQL select statement.
To give an example, in MySQL you can use the LIMIT clause of the SELECT statement to specify how many rows to return and the offset:
SELECT *
FROM catalog
WHERE sku LIKE '1W%'
ORDER by id
LIMIT 25, 9999999999
which returns rows 26 to 9999999999 of the query results.
Create an index on the column sku (if valid make it unique). How many rows are there in the table?
SELECT sku
FROM catalog
WHER sku LIKE '1W%
ORDER BY __SOME COLUMN __
LIMIT 10000 OFFSET 25
This is returning all* the rows in the database that are after row 25 (OFFSET 25).
*LIMIT 10000 constraints the resulting query to 10000 tuples (rows).
To ensure you are not getting a random OFFSET, you would need to order by some column.

sql get max based on field

I need to get the ID based from what ever the max amount is. Below is giving me an error
select ID from Prog
where Amount = MAX(Amount)
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
The end result is that I need to get the just the ID as I need to pass it something else that is expecting it.
You need to order by Amount and select 1 record instead...
SELECT ID
FROM Prog
ORDER BY Amount DESC
LIMIT 1;
This takes all the rows in Prog, orders them in descending order by Amount (in other words, the first sorted row has the highest Amount), then limits the query to select only one row (the one with the highest Amount).
Also, subqueries are bad for performance. This code runs on a table with 200k records in half the time as the subquery versions.
Just pass a subquery with the max value to the where clause :
select ID from Prog
where Amount = (SELECT MAX(Amount) from Prog)
If you're using SQL Server that should do it :
SELECT TOP 1 ID
FROM Prog
ORDER BY Amount DESC
This should be something like:
select P.ID from Prog P
where P.Amount = (select max(Amount) from Prog)
EDIT:
If you really want only 1 row, you should do:
select max(P.ID) from Prog P
where P.Amount = (select max(Amount) from Prog);
However, if you have multiple rows that would match amount and you only want 1 row, you should have some kind of logic behind how you pick your one row. Not just relying on this max trick, or limit 1 type logic.
Also, I don't write limit 1, because this is not ANSI sql -- it works in mysql but OP doesn't say what he wants. Every db is different -- see here: Is there an ANSI SQL alternative to the MYSQL LIMIT keyword? Don't get used to one db's extensions unless you only want to work in 1 db for the rest of your life.
select min(ID) from Prog
where Amount in
(
select max(amount)
from prog
)
The min statement ensures that you get only one result.