SQL Select All Without Values in Another Table - c#

I'm building an application to manage tools that are on loan to staff members and the way that the table is set up is there has a Tools table which has a unique tool code and serial number and a Loans table that contains the unique tool code and a return date. Each time there is a loan, it creates a new entry, the return date when the loan is created is null.
The query I have at the moment searches for all tools based on a text input. I've tried a lot of code with inner joins with no success and as I'm not extremely experienced with SQL, I couldn't figure out how to make it work.
SELECT [Tools].[ToolID], [Tools].[Type], [Tools].[Brand], [Tools].[Serial], [Tools].[Year], [Tools].[Code] FROM [Tools]
WHERE ([Tools].Serial LIKE '%234%' OR [Tools].Code LIKE '%234%')
My issue occurs when I'm searching for a tool in the loan database. I want it to show tools from the Tools table that:
A) Have no entries in the loan database (i.e. a new tool)
B) All entries in the database have a return date (tool has been returned)
Thanks.
EDIT: Combined the two queries from the answer
SELECT [Tools].[ToolID], [Tools].[Type], [Tools].[Brand], [Tools].[Serial], [Tools].[Year], [Tools].[Code]
FROM [Tools] left outer join
Loan ON [Tools].code = Loan.toolcode
WHERE Loan.toolcode is null AND ([Tools].Code LIKE '%234%' OR [Tools].Serial LIKE '%234%')
UNION
SELECT [Tools].[ToolID], [Tools].[Type], [Tools].[Brand], [Tools].[Serial], [Tools].[Year], [Tools].[Code]
FROM Loan
INNER JOIN Tools ON Tools.Code = Loan.ToolCode
GROUP BY [Tools].[ToolID], [Tools].[Type], [Tools].[Brand], [Tools].[Serial], [Tools].[Year], [Tools].[Code]
HAVING count(returndate) = count(*)

To show tools that have no entry in the loan database:
SELECT t.*
from tools t left outer join
loans l
on t.code = l.toolcode WHERE l.toolcode is null;
I assume that for the second question, you want all tools where all entries have a return date -- that is, no entry is NULL:
select l.toolcode
from loans l
group by l.toolcode
having sum(case when returndate is null then 1 else 0 end) = 0
This formulation counts up the number of records where the returndate is null and only returns tools where there are no such records. An alternative way of writing the same logic is:
having count(returndate) = count(*)

Related

How to Return Dynamic Table using Stored Procedure

I have two tables tblCustBilIinfo with
(Bill_no,Customer_Name,date,bill_Amount,deposit,Balance)
And tblincome with (Tid,date,name,amount)
Now I need to show record like this
Select c.Bill_Amount,I.Amount ,C.balance from tblcustBillInfo as C, tblincome As I
where C.customer_Name ='rakesh'
and date between '24-06-2016' And '30-06-2016'
Now selected record is like in Balance sheet format Like in accounting (debit credit.)
First Select Bill_ amount then debit amount of customer.
And also need to select date column but it values is selected from above tables on the bases of selected record.
Please can any one Help me to solve.
Or guide me to use procedure or function to achieve that task.
NO, you can't get data from both table like that unless doing a JOIN between the tables either with a related column (OR) using a common naming column.Some thing like
select c.Bill_Amount,
I.Amount ,
C.balance
from tblcustBillInfo as C JOIN tblincome As I ON C.id = I.Tid
where C.customer_Name = 'rakesh'
and C.date between '24-06-2016' And '30-06-2016'

Create an ordered table

I am not sure if I titled this question correctly, here is my question. I have a table that has Products and these products have various details including buying price, selling price, initial stock quantity, number of items sold, number of items remaining. I then have another table with sales information based on location of the buyer lets call it LocationSales. I need to create a table that will show the products and the location information like in the snapshot below.
I made the representation using Excel. I had already achieved this while working on a project earlier last year but it involved a lot or hard-coding and stack-overflow exceptions. I would like to achieve this more effectively. This is a hypothetical representation of my actual problem. I have tried using hierarchical tables before using Telerik UI which worked well but did not display the information quite as required by my superiors. I would really appreciate it if someone would point me to the right direction. I understand it's impossible to address the entire problem here but I would appreciate someone including a link to a blog post or video or some literature that can assist me. PS. I have tried database views as well, didn't work as required.
I am using ASP.NET C# MVC5 with Visual Studio 2013 and the database as SQL Server 2012
EDIT://Tables I am using
EDIT 2:///
As per my research so far i have managed to obtain the following
SQL CODE://
select * from
(select
locationName
,productName as [PRODUCT]
,roadTransfer
,airTransfer
,initialQty
,soldQty
,remQty
from
Location as l inner join
Sales as s on l.locationID=s.locationID
inner join
Product as p on p.productID=s.productID
)as BaseData
pivot(
count(roadTransfer)
for locationName
in([Germany]
,[Kenya]
) as SummaryTable
order by Product asc
I used a pivot table. I am currently trying to get both the road and air transfer. I I will try using a GROUP BY clause and see what I can do. I will post an update when I have the full solution.
So at this point (Edit 2) you have created a pivot for road transfer. Unfortunately you can't aggregate more than one value in a pivot, so the way round it is to do two pivots and join the results together. You result set therefore has 3 query parts to produce the query
A list of products
Pivoted Road Transfer amounts by country
Pivoted Air Transfer amounts by country
If you left join all of them together in a single query on the product ID you will get close to your query, but the column order won't be quite right i.e. all the Road Transfers will come before the Air Transfers.
I have created a SQLFiddle demonstrating this
Select p.prodName AS Product,
p.initialQty AS [Initial Quantity],
p.sold AS [Quantity Sold],
p.remaining AS [Quantity Remaining],
AirT.[Air Transfer - Germany],
RoadT.[Road Transfer - Germany],
AirT.[Air Transfer - Kenya],
RoadT.[Road Transfer - Kenya]
FROM Products p
LEFT JOIN (
SELECT productID, [Germany] AS [Air Transfer - Germany], [Kenya] AS [Air Transfer - Kenya]
FROM (select productID, l.locName, qty
FROM sales s
INNER JOIN Locations l on l.locID = s.locID
where transfer = 'Air Transfer') as SourceTable
PIVOT (SUM(qty)
FOR locName IN ([Germany], [Kenya])
) As AirTransfers
) AirT on AirT.productID = p.ProductID
LEFT JOIN (
SELECT productID, [Germany] AS [Road Transfer - Germany], [Kenya] AS [Road Transfer - Kenya]
FROM (select productID, l.locName, qty
FROM sales s
INNER JOIN Locations l on l.locID = s.locID
where transfer = 'Road Transfer') as SourceTable
PIVOT (SUM(qty)
FOR locName IN ([Germany], [Kenya])
) As RoadTransfers
) RoadT on RoadT.productID = p.ProductID

Counting records from database and inserting data into a GridView

Good morning,
I have been trying to get my mind around doing a simple count of records in an application I am making in visual studio.
The database associated with the application keeps records of people each of them belonging in a certain department. Within the application I want to create a statistics window which counts how many people of each department are currently kept in the database.
In my mind the way to do this would be to select distint values from the department column and then for each result to query again with the count method in order to get a value for each, however I feel this is not the quite correct way to do so.
What I want pretty much is to have a window with a grid view in which the first column holds the name of the department and the second one holds the number of people in that very same department but due to actually beeing new to visual studio and programming in general I couldn't quite figure out how to do this.
Any help would be appreciated.
you can do it by simple join query in database . try following query :
SELECT A.ID , SUM(CASE WHEN B.ID IS NOT NULL THEN 1 ELSE 0 END) AS TOTALNOOFPEOPLE
FROM DEPARTMENT AS A LEFT OUTER JOIN PEOPLE AS B ON A.ID = B.DEPARTMENTID
GROUP BY A.ID
CREATE TABLE [dbo].[Dept]([DeptName] varchar NULL,
[StudName] varchar NULL)
select DeptName,count(*) as NoOfPeople from [sample].[dbo].[Dept] group by [DeptName]
In windows form
SqlDataAdapter sda=new SqlDataAdapter ('select DeptName,count(*) as NoOfPeople from [sample].[dbo].[Dept] group by [DeptName]',con)
DataTable dt=new DataTable();
sda.fill(dt);
dataGridView1.DataSourc=dt;
dataGridView1.DataBind();

Find Unused ID in Database using C# and SQL

I am trying to code a simple database management tool in C#. I am in the process of coding a function to insert a new row into the database, but I have run into a problem. I need to be able to detect which ID numbers are not already taken. I have done some research but haven't found any clear answers.
Example table:
ID Name
---------------
1 John
2 Linda
4 Mark
5 Jessica
How would I add a function that automatically detects that ID 3 is empty, and places a new entry there?
Edit: My real question is; When I want to insert a new row via C#, how do I handle a column which is auto-increment? An example would be fantastic :)
I don't like giving answers like this...but I am going to anyway on this occasion.
Don't
What if you store more data in another table which has a foreign key to the ID in this table? If you reuse numbers you are asking for trouble with referential integrity down the line.
I assume your field is an int? If so, an auto increment should give more than enough for most purposes. It makes your insert simpler, and maintains integrity.
Edit: You might have a very good reason to do it, but I wanted to make the point in case somebody comes along and sees this later on who thinks it is a good idea.
SQL:
SELECT ID From TABLE
OR
SELECT t.ID
FROM ( SELECT number + 1 AS ID
FROM master.dbo.spt_values
WHERE Type = 'p'
AND number <= ( SELECT MAX(ID) - 1
FROM #Table
)
) t
LEFT JOIN #Table ON t.ID = [#Table].ID
WHERE [#Table].ID IS NULL
C#
DataTable dt = new DataTable();
//Populate Dt with SQL
var tableInts = dt.Rows.Cast<DataRow>().Select(row => row.Field<int>("ID")).ToList<int>();
var allInts = Enumerable.Range(1, tableInts.Max()).ToList();
var minInt = allInts.Except(tableInts).Min();
SELECT #temp.Id
FROM #temp
LEFT JOIN table1 ON #temp.Id = table1.Id
WHERE table1.Id IS NULL
Try this?
But my suggestion is, just autoincrement the field.
How you do that is, you set the IDENTITY property of the column to true, and set it as Primary key too(not null).
To handle inserts, you might need triggers, which are like stored procedures, but they can act in place of insert or update or delete, or before/after insert/update/delete
Google triggers.
from How do I find a "gap" in running counter with SQL?
select
MIN(ID)
from (
select
0 ID
union all
select
[YourIdColumn]+1
from
[YourTable]
where
--Filter the rest of your key--
) foo
left join
[YourTable]
on [YourIdColumn]=ID
and --Filter the rest of your key--
where
[YourIdColumn] is null

Turning a table "on it's side" in asp.net - how?

How do I turn this table:
+------------+-----------------+
| Category + Subcategory |
+------------+-----------------+
|Cat..........+ Persian.........|
|Cat..........+ Siamese........|
|Cat..........+ Tabby...........|
|Dog.........+ Poodle..........|
|Dog.........+ Boxer............|
+------------+----------------+
on it's side to get the following:
+------------+-----------------+
| Cat......... + Dog............. |
+------------+-----------------+
+ Persian..+ Poodle.........+
+ Siamese + Boxer...........+
+ Burmese + ...................+
+------------+-----------------+
The initial table is from the following MySQL query:
select c.CATEGORYNAME, sc.NAME from subcategorydefinition sc
join categorydefinition c on sc.CATEGORYID = c.CATEGORYID
where c.ISDELETED = 0
order by CATEGORYNAME, NAME ASC
And I want to display it in (probably) a Gridview.
Cheers!
Pivot is static in SQL. You need to know in advance the columns you want in output, so if the list of categories is not fixed, you can't use pivot directly.
If you were using Microsoft SQL Server (which I know you're not, but it's for the sake of example), you could use a dynamic query in a stored procedure, as described here:
http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
Now, in MySql, there is no way to execute dynamic SQL on the sql side (no equivalent of EXECUTE or sp_executeqsl), so your best choice would be to generate a similar SQL query server-side (aspnet server-side).
Another simpler idea IMHO would be to forget about doing it in SQL, but to do the aggregation in your C# code.
You should use pivot
To do this in SQL, you'd need to dynamically generate your query based on the available set of values in the "Category" column. This is usually fairly painful and error prone, regardless of whether you do it in pure SQL (in a sproc) or in code (dynamic SQL).
I'd recommend reading your values from the database in the way that they are stored, then dynamically creating a DataTable or similar structure to use as the datasource for your UI.
I don't have a working version of MySql handy but this will work as long as there is always more cats than dogs because of the left join at the end of the script. I forgot that there isn't a full outer join in MySql but you could use this logic to try it out.
But the point of this is that if you have two tables with arbitrary keys you can join on the keys to get the results lined up like you want.
-- drop tables
DROP TABLE dbo.cat
DROP TABLE dbo.dog
--create dog table
create table dog (
dog_id int IDENTITY(1,1) NOT NULL
,dog varchar(50)
)
--add dogs only
insert into dog (dog)
select subcategory
FROM play.dbo.test
where category = 'Dog'
--create cat table
create table cat (
cat_id int IDENTITY(1,1) NOT NULL
,cat varchar(50)
)
--add cats only
insert into cat (cat)
select subcategory
FROM play.dbo.test
where category = 'cat'
-- disply everything
SELECT cat
, dog
from dog d
--full outer join cat c
left join dog d
on d.dog_id = c.cat_id

Categories